aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/acpica/actables.h6
-rw-r--r--drivers/acpi/acpica/tbfadt.c14
-rw-r--r--drivers/acpi/acpica/tbutils.c85
-rw-r--r--drivers/acpi/acpica/tbxface.c130
-rw-r--r--drivers/acpi/bus.c2
-rw-r--r--drivers/acpi/nfit/core.c3
-rw-r--r--drivers/acpi/numa.c2
-rw-r--r--drivers/acpi/osl.c15
-rw-r--r--drivers/acpi/processor_core.c8
-rw-r--r--drivers/acpi/scan.c3
-rw-r--r--drivers/acpi/spcr.c8
-rw-r--r--drivers/acpi/tables.c17
-rw-r--r--drivers/base/cacheinfo.c5
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c2
-rw-r--r--drivers/cpufreq/s3c64xx-cpufreq.c2
-rw-r--r--drivers/dax/dax.c94
-rw-r--r--drivers/dax/pmem.c3
-rw-r--r--drivers/firmware/dmi_scan.c4
-rw-r--r--drivers/gpio/gpio-tps65218.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c3
-rw-r--r--drivers/gpu/drm/i915/Kconfig1
-rw-r--r--drivers/gpu/drm/i915/gvt/Makefile2
-rw-r--r--drivers/gpu/drm/i915/gvt/gvt.h6
-rw-r--r--drivers/gpu/drm/i915/gvt/kvmgt.c975
-rw-r--r--drivers/gpu/drm/radeon/radeon_bios.c3
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c31
-rw-r--r--drivers/i2c/busses/i2c-octeon-core.c4
-rw-r--r--drivers/i2c/busses/i2c-octeon-core.h21
-rw-r--r--drivers/i2c/busses/i2c-xgene-slimpro.c1
-rw-r--r--drivers/i2c/muxes/i2c-mux-mlxcpld.c24
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca954x.c5
-rw-r--r--drivers/input/joystick/xpad.c7
-rw-r--r--drivers/input/keyboard/gpio_keys.c190
-rw-r--r--drivers/input/keyboard/gpio_keys_polled.c128
-rw-r--r--drivers/input/keyboard/lpc32xx-keys.c2
-rw-r--r--drivers/input/keyboard/pxa27x_keypad.c2
-rw-r--r--drivers/input/keyboard/tca8418_keypad.c21
-rw-r--r--drivers/input/misc/Kconfig7
-rw-r--r--drivers/input/misc/bma150.c9
-rw-r--r--drivers/input/misc/da9063_onkey.c9
-rw-r--r--drivers/input/misc/drv260x.c119
-rw-r--r--drivers/input/misc/drv2665.c6
-rw-r--r--drivers/input/misc/drv2667.c4
-rw-r--r--drivers/input/misc/soc_button_array.c8
-rw-r--r--drivers/input/misc/tps65218-pwrbutton.c8
-rw-r--r--drivers/input/mouse/alps.c56
-rw-r--r--drivers/input/mouse/alps.h24
-rw-r--r--drivers/input/mouse/elan_i2c_core.c17
-rw-r--r--drivers/input/rmi4/Kconfig42
-rw-r--r--drivers/input/rmi4/Makefile4
-rw-r--r--drivers/input/rmi4/rmi_2d_sensor.c10
-rw-r--r--drivers/input/rmi4/rmi_2d_sensor.h2
-rw-r--r--drivers/input/rmi4/rmi_bus.c12
-rw-r--r--drivers/input/rmi4/rmi_bus.h12
-rw-r--r--drivers/input/rmi4/rmi_driver.c420
-rw-r--r--drivers/input/rmi4/rmi_driver.h31
-rw-r--r--drivers/input/rmi4/rmi_f01.c12
-rw-r--r--drivers/input/rmi4/rmi_f03.c250
-rw-r--r--drivers/input/rmi4/rmi_f11.c98
-rw-r--r--drivers/input/rmi4/rmi_f12.c146
-rw-r--r--drivers/input/rmi4/rmi_f30.c22
-rw-r--r--drivers/input/rmi4/rmi_f34.c516
-rw-r--r--drivers/input/rmi4/rmi_f34.h314
-rw-r--r--drivers/input/rmi4/rmi_f34v7.c1372
-rw-r--r--drivers/input/rmi4/rmi_f54.c19
-rw-r--r--drivers/input/rmi4/rmi_f55.c131
-rw-r--r--drivers/input/rmi4/rmi_i2c.c74
-rw-r--r--drivers/input/rmi4/rmi_smbus.c447
-rw-r--r--drivers/input/rmi4/rmi_spi.c72
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h78
-rw-r--r--drivers/input/serio/i8042.c2
-rw-r--r--drivers/input/touchscreen/fsl-imx25-tcq.c1
-rw-r--r--drivers/input/touchscreen/imx6ul_tsc.c83
-rw-r--r--drivers/input/touchscreen/melfas_mip4.c51
-rw-r--r--drivers/input/touchscreen/raydium_i2c_ts.c2
-rw-r--r--drivers/input/touchscreen/silead.c29
-rw-r--r--drivers/iommu/amd_iommu_init.c10
-rw-r--r--drivers/iommu/dmar.c7
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c32
-rw-r--r--drivers/isdn/gigaset/ser-gigaset.c32
-rw-r--r--drivers/isdn/gigaset/usb-gigaset.c32
-rw-r--r--drivers/isdn/hisax/config.c16
-rw-r--r--drivers/isdn/hisax/hisax.h4
-rw-r--r--drivers/isdn/i4l/isdn_concap.c6
-rw-r--r--drivers/isdn/i4l/isdn_x25iface.c16
-rw-r--r--drivers/mailbox/bcm-pdc-mailbox.c548
-rw-r--r--drivers/mailbox/mailbox-sti.c1
-rw-r--r--drivers/mailbox/mailbox-test.c92
-rw-r--r--drivers/mailbox/pcc.c5
-rw-r--r--drivers/mfd/Kconfig26
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/ab3100-core.c39
-rw-r--r--drivers/mfd/ab8500-core.c37
-rw-r--r--drivers/mfd/ab8500-debugfs.c21
-rw-r--r--drivers/mfd/ab8500-gpadc.c19
-rw-r--r--drivers/mfd/ab8500-sysctrl.c9
-rw-r--r--drivers/mfd/abx500-core.c7
-rw-r--r--drivers/mfd/arizona-core.c1
-rw-r--r--drivers/mfd/arizona-irq.c8
-rw-r--r--drivers/mfd/axp20x-i2c.c7
-rw-r--r--drivers/mfd/axp20x.c4
-rw-r--r--drivers/mfd/bcm590xx.c2
-rw-r--r--drivers/mfd/cs47l24-tables.c6
-rw-r--r--drivers/mfd/davinci_voicecodec.c1
-rw-r--r--drivers/mfd/fsl-imx25-tsadc.c1
-rw-r--r--drivers/mfd/hi655x-pmic.c1
-rw-r--r--drivers/mfd/intel-lpss-pci.c1
-rw-r--r--drivers/mfd/intel_soc_pmic_bxtwc.c40
-rw-r--r--drivers/mfd/lpc_ich.c2
-rw-r--r--drivers/mfd/palmas.c3
-rw-r--r--drivers/mfd/qcom-pm8xxx.c231
-rw-r--r--drivers/mfd/rk808.c23
-rw-r--r--drivers/mfd/rn5t618.c1
-rw-r--r--drivers/mfd/si476x-i2c.c2
-rw-r--r--drivers/mfd/sun4i-gpadc.c181
-rw-r--r--drivers/mfd/tc3589x.c4
-rw-r--r--drivers/mfd/tps65217.c71
-rw-r--r--drivers/mfd/tps65218.c34
-rw-r--r--drivers/mfd/tps65912-core.c17
-rw-r--r--drivers/mfd/wm5102-tables.c1412
-rw-r--r--drivers/mfd/wm8994-core.c6
-rw-r--r--drivers/mmc/core/core.c12
-rw-r--r--drivers/mmc/core/sd.c12
-rw-r--r--drivers/mmc/host/sdhci-cadence.c1
-rw-r--r--drivers/mmc/host/sdhci.c33
-rw-r--r--drivers/mtd/bcm47xxpart.c10
-rw-r--r--drivers/mtd/devices/bcm47xxsflash.c24
-rw-r--r--drivers/mtd/maps/sc520cdp.c8
-rw-r--r--drivers/mtd/mtdcore.c44
-rw-r--r--drivers/mtd/mtdswap.c2
-rw-r--r--drivers/mtd/nand/Kconfig21
-rw-r--r--drivers/mtd/nand/Makefile2
-rw-r--r--drivers/mtd/nand/ams-delta.c5
-rw-r--r--drivers/mtd/nand/atmel_nand.c10
-rw-r--r--drivers/mtd/nand/brcmnand/brcmnand.c10
-rw-r--r--drivers/mtd/nand/cafe_nand.c5
-rw-r--r--drivers/mtd/nand/cmx270_nand.c4
-rw-r--r--drivers/mtd/nand/cs553x_nand.c5
-rw-r--r--drivers/mtd/nand/denali.c101
-rw-r--r--drivers/mtd/nand/denali.h12
-rw-r--r--drivers/mtd/nand/denali_dt.c3
-rw-r--r--drivers/mtd/nand/denali_pci.c1
-rw-r--r--drivers/mtd/nand/fsmc_nand.c9
-rw-r--r--drivers/mtd/nand/gpio.c5
-rw-r--r--drivers/mtd/nand/hisi504_nand.c4
-rw-r--r--drivers/mtd/nand/lpc32xx_mlc.c10
-rw-r--r--drivers/mtd/nand/lpc32xx_slc.c10
-rw-r--r--drivers/mtd/nand/mpc5121_nfc.c4
-rw-r--r--drivers/mtd/nand/mtk_nand.c4
-rw-r--r--drivers/mtd/nand/mxc_nand.c10
-rw-r--r--drivers/mtd/nand/nand_base.c84
-rw-r--r--drivers/mtd/nand/nand_ids.c3
-rw-r--r--drivers/mtd/nand/nand_timings.c26
-rw-r--r--drivers/mtd/nand/nandsim.c19
-rw-r--r--drivers/mtd/nand/omap2.c10
-rw-r--r--drivers/mtd/nand/orion_nand.c5
-rw-r--r--drivers/mtd/nand/oxnas_nand.c195
-rw-r--r--drivers/mtd/nand/pasemi_nand.c5
-rw-r--r--drivers/mtd/nand/plat_nand.c5
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c22
-rw-r--r--drivers/mtd/nand/s3c2410.c286
-rw-r--r--drivers/mtd/nand/socrates_nand.c12
-rw-r--r--drivers/mtd/nand/sunxi_nand.c4
-rw-r--r--drivers/mtd/nand/tango_nand.c676
-rw-r--r--drivers/mtd/nand/tmio_nand.c6
-rw-r--r--drivers/mtd/nand/vf610_nfc.c10
-rw-r--r--drivers/mtd/spi-nor/cadence-quadspi.c6
-rw-r--r--drivers/mtd/spi-nor/fsl-quadspi.c8
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c14
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.c6
-rw-r--r--drivers/net/ethernet/3com/3c515.c15
-rw-r--r--drivers/net/ethernet/Kconfig1
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_enet.c8
-rw-r--r--drivers/net/ethernet/cadence/Kconfig9
-rw-r--r--drivers/net/ethernet/cadence/Makefile1
-rw-r--r--drivers/net/ethernet/cadence/macb.c31
-rw-r--r--drivers/net/ethernet/cadence/macb_pci.c153
-rw-r--r--drivers/net/ethernet/cavium/octeon/octeon_mgmt.c6
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/cxgb2.c64
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c65
-rw-r--r--drivers/net/ethernet/cirrus/ep93xx_eth.c14
-rw-r--r--drivers/net/ethernet/davicom/dm9000.c14
-rw-r--r--drivers/net/ethernet/freescale/dpaa/Kconfig2
-rw-r--r--drivers/net/ethernet/freescale/dpaa/dpaa_eth.c71
-rw-r--r--drivers/net/ethernet/freescale/fman/Kconfig2
-rw-r--r--drivers/net/ethernet/freescale/fman/fman.c15
-rw-r--r--drivers/net/ethernet/freescale/fman/mac.c1
-rw-r--r--drivers/net/ethernet/hisilicon/hip04_eth.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hisi_femac.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hix5hd2_gmac.c13
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c12
-rw-r--r--drivers/net/ethernet/marvell/mv643xx_eth.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c2
-rw-r--r--drivers/net/ethernet/microchip/encx24j600-regmap.c17
-rw-r--r--drivers/net/ethernet/microchip/encx24j600.c19
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_iscsi.c2
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac.c9
-rw-r--r--drivers/net/ethernet/rdc/r6040.c10
-rw-r--r--drivers/net/ethernet/sfc/Kconfig21
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c35
-rw-r--r--drivers/net/ethernet/sfc/mcdi_port.c60
-rw-r--r--drivers/net/ethernet/sfc/net_driver.h12
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/enh_desc.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c8
-rw-r--r--drivers/net/ethernet/ti/netcp_ethss.c24
-rw-r--r--drivers/net/gtp.c8
-rw-r--r--drivers/net/irda/w83977af_ir.c6
-rw-r--r--drivers/net/phy/phy_device.c22
-rw-r--r--drivers/net/virtio_net.c369
-rw-r--r--drivers/net/vrf.c6
-rw-r--r--drivers/net/wan/lmc/lmc_media.c97
-rw-r--r--drivers/nvdimm/claim.c46
-rw-r--r--drivers/nvdimm/core.c29
-rw-r--r--drivers/nvdimm/dimm.c2
-rw-r--r--drivers/nvdimm/dimm_devs.c7
-rw-r--r--drivers/nvdimm/e820.c12
-rw-r--r--drivers/nvdimm/label.c2
-rw-r--r--drivers/nvdimm/namespace_devs.c8
-rw-r--r--drivers/nvdimm/nd.h12
-rw-r--r--drivers/nvdimm/pfn_devs.c2
-rw-r--r--drivers/nvdimm/pmem.c21
-rw-r--r--drivers/nvdimm/region_devs.c2
-rw-r--r--drivers/oprofile/buffer_sync.c2
-rw-r--r--drivers/platform/x86/Kconfig40
-rw-r--r--drivers/platform/x86/Makefile4
-rw-r--r--drivers/platform/x86/ideapad-laptop.c7
-rw-r--r--drivers/platform/x86/intel_bxtwc_tmu.c162
-rw-r--r--drivers/platform/x86/mlx-platform.c361
-rw-r--r--drivers/platform/x86/surface3-wmi.c297
-rw-r--r--drivers/platform/x86/surface3_button.c250
-rw-r--r--drivers/regulator/tps65218-regulator.c153
-rw-r--r--drivers/rtc/Kconfig38
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-cmos.c75
-rw-r--r--drivers/rtc/rtc-ds1307.c52
-rw-r--r--drivers/rtc/rtc-ds1374.c4
-rw-r--r--drivers/rtc/rtc-imxdi.c2
-rw-r--r--drivers/rtc/rtc-jz4740.c154
-rw-r--r--drivers/rtc/rtc-lib.c4
-rw-r--r--drivers/rtc/rtc-mcp795.c122
-rw-r--r--drivers/rtc/rtc-pcf85063.c7
-rw-r--r--drivers/rtc/rtc-r7301.c453
-rw-r--r--drivers/rtc/rtc-starfire.c10
-rw-r--r--drivers/rtc/rtc-sun4v.c10
-rw-r--r--drivers/rtc/rtc-twl.c202
-rw-r--r--drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c1
-rw-r--r--drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h1
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c1
-rw-r--r--drivers/staging/lustre/lustre/llite/symlink.c1
-rw-r--r--drivers/target/iscsi/cxgbit/cxgbit_target.c1
-rw-r--r--drivers/target/iscsi/iscsi_target.c2
-rw-r--r--drivers/target/iscsi/iscsi_target.h12
-rw-r--r--drivers/target/iscsi/iscsi_target_auth.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_auth.h5
-rw-r--r--drivers/target/iscsi/iscsi_target_configfs.c7
-rw-r--r--drivers/target/iscsi/iscsi_target_datain_values.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_datain_values.h3
-rw-r--r--drivers/target/iscsi/iscsi_target_device.h3
-rw-r--r--drivers/target/iscsi/iscsi_target_erl0.h6
-rw-r--r--drivers/target/iscsi/iscsi_target_erl1.c1
-rw-r--r--drivers/target/iscsi/iscsi_target_erl1.h10
-rw-r--r--drivers/target/iscsi/iscsi_target_erl2.c1
-rw-r--r--drivers/target/iscsi/iscsi_target_erl2.h7
-rw-r--r--drivers/target/iscsi/iscsi_target_login.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_login.h7
-rw-r--r--drivers/target/iscsi/iscsi_target_nego.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_nego.h4
-rw-r--r--drivers/target/iscsi/iscsi_target_nodeattrib.h5
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.h6
-rw-r--r--drivers/target/iscsi/iscsi_target_seq_pdu_list.h5
-rw-r--r--drivers/target/iscsi/iscsi_target_tmr.h6
-rw-r--r--drivers/target/iscsi/iscsi_target_tpg.c3
-rw-r--r--drivers/target/iscsi/iscsi_target_tpg.h9
-rw-r--r--drivers/target/iscsi/iscsi_target_transport.c1
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c1
-rw-r--r--drivers/target/iscsi/iscsi_target_util.h8
-rw-r--r--drivers/target/loopback/tcm_loop.h4
-rw-r--r--drivers/target/sbp/sbp_target.c3
-rw-r--r--drivers/target/target_core_alua.c3
-rw-r--r--drivers/target/target_core_alua.h2
-rw-r--r--drivers/target/target_core_configfs.c4
-rw-r--r--drivers/target/target_core_device.c1
-rw-r--r--drivers/target/target_core_file.c1
-rw-r--r--drivers/target/target_core_file.h2
-rw-r--r--drivers/target/target_core_iblock.h3
-rw-r--r--drivers/target/target_core_internal.h5
-rw-r--r--drivers/target/target_core_pr.c5
-rw-r--r--drivers/target/target_core_pr.h4
-rw-r--r--drivers/target/target_core_pscsi.h7
-rw-r--r--drivers/target/target_core_rd.c2
-rw-r--r--drivers/target/target_core_rd.h4
-rw-r--r--drivers/target/target_core_sbc.c1
-rw-r--r--drivers/target/target_core_ua.h2
-rw-r--r--drivers/target/target_core_user.c5
-rw-r--r--drivers/target/target_core_xcopy.c1
-rw-r--r--drivers/target/target_core_xcopy.h2
-rw-r--r--drivers/target/tcm_fc/tcm_fc.h3
-rw-r--r--drivers/usb/gadget/function/f_tcm.c2
301 files changed, 12021 insertions, 3116 deletions
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h
index 7dd527f8ca1d..94be8a8e6c08 100644
--- a/drivers/acpi/acpica/actables.h
+++ b/drivers/acpi/acpica/actables.h
@@ -166,6 +166,12 @@ acpi_tb_install_table_with_override(struct acpi_table_desc *new_table_desc,
acpi_status acpi_tb_parse_root_table(acpi_physical_address rsdp_address);
+acpi_status
+acpi_tb_get_table(struct acpi_table_desc *table_desc,
+ struct acpi_table_header **out_table);
+
+void acpi_tb_put_table(struct acpi_table_desc *table_desc);
+
/*
* tbxfload
*/
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index 5fb838e592dc..81473a4880ce 100644
--- a/drivers/acpi/acpica/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -311,6 +311,8 @@ void acpi_tb_parse_fadt(void)
{
u32 length;
struct acpi_table_header *table;
+ struct acpi_table_desc *fadt_desc;
+ acpi_status status;
/*
* The FADT has multiple versions with different lengths,
@@ -319,14 +321,12 @@ void acpi_tb_parse_fadt(void)
* Get a local copy of the FADT and convert it to a common format
* Map entire FADT, assumed to be smaller than one page.
*/
- length = acpi_gbl_root_table_list.tables[acpi_gbl_fadt_index].length;
-
- table =
- acpi_os_map_memory(acpi_gbl_root_table_list.
- tables[acpi_gbl_fadt_index].address, length);
- if (!table) {
+ fadt_desc = &acpi_gbl_root_table_list.tables[acpi_gbl_fadt_index];
+ status = acpi_tb_get_table(fadt_desc, &table);
+ if (ACPI_FAILURE(status)) {
return;
}
+ length = fadt_desc->length;
/*
* Validate the FADT checksum before we copy the table. Ignore
@@ -340,7 +340,7 @@ void acpi_tb_parse_fadt(void)
/* All done with the real FADT, unmap it */
- acpi_os_unmap_memory(table, length);
+ acpi_tb_put_table(fadt_desc);
/* Obtain the DSDT and FACS tables via their addresses within the FADT */
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 51eb07cf9898..86854e846800 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -381,3 +381,88 @@ next_table:
acpi_os_unmap_memory(table, length);
return_ACPI_STATUS(AE_OK);
}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_get_table
+ *
+ * PARAMETERS: table_desc - Table descriptor
+ * out_table - Where the pointer to the table is returned
+ *
+ * RETURN: Status and pointer to the requested table
+ *
+ * DESCRIPTION: Increase a reference to a table descriptor and return the
+ * validated table pointer.
+ * If the table descriptor is an entry of the root table list,
+ * this API must be invoked with ACPI_MTX_TABLES acquired.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_get_table(struct acpi_table_desc *table_desc,
+ struct acpi_table_header **out_table)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_tb_get_table);
+
+ if (table_desc->validation_count == 0) {
+
+ /* Table need to be "VALIDATED" */
+
+ status = acpi_tb_validate_table(table_desc);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ }
+
+ table_desc->validation_count++;
+ if (table_desc->validation_count == 0) {
+ ACPI_ERROR((AE_INFO,
+ "Table %p, Validation count is zero after increment\n",
+ table_desc));
+ table_desc->validation_count--;
+ return_ACPI_STATUS(AE_LIMIT);
+ }
+
+ *out_table = table_desc->pointer;
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_put_table
+ *
+ * PARAMETERS: table_desc - Table descriptor
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Decrease a reference to a table descriptor and release the
+ * validated table pointer if no references.
+ * If the table descriptor is an entry of the root table list,
+ * this API must be invoked with ACPI_MTX_TABLES acquired.
+ *
+ ******************************************************************************/
+
+void acpi_tb_put_table(struct acpi_table_desc *table_desc)
+{
+
+ ACPI_FUNCTION_TRACE(acpi_tb_put_table);
+
+ if (table_desc->validation_count == 0) {
+ ACPI_WARNING((AE_INFO,
+ "Table %p, Validation count is zero before decrement\n",
+ table_desc));
+ return_VOID;
+ }
+ table_desc->validation_count--;
+
+ if (table_desc->validation_count == 0) {
+
+ /* Table need to be "INVALIDATED" */
+
+ acpi_tb_invalidate_table(table_desc);
+ }
+
+ return_VOID;
+}
diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c
index d5adb7ac4684..7684707b254b 100644
--- a/drivers/acpi/acpica/tbxface.c
+++ b/drivers/acpi/acpica/tbxface.c
@@ -282,7 +282,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_table_header)
/*******************************************************************************
*
- * FUNCTION: acpi_get_table_with_size
+ * FUNCTION: acpi_get_table
*
* PARAMETERS: signature - ACPI signature of needed table
* instance - Which instance (for SSDTs)
@@ -292,16 +292,21 @@ ACPI_EXPORT_SYMBOL(acpi_get_table_header)
*
* DESCRIPTION: Finds and verifies an ACPI table. Table must be in the
* RSDT/XSDT.
+ * Note that an early stage acpi_get_table() call must be paired
+ * with an early stage acpi_put_table() call. otherwise the table
+ * pointer mapped by the early stage mapping implementation may be
+ * erroneously unmapped by the late stage unmapping implementation
+ * in an acpi_put_table() invoked during the late stage.
*
******************************************************************************/
acpi_status
-acpi_get_table_with_size(char *signature,
- u32 instance, struct acpi_table_header **out_table,
- acpi_size *tbl_size)
+acpi_get_table(char *signature,
+ u32 instance, struct acpi_table_header ** out_table)
{
u32 i;
u32 j;
- acpi_status status;
+ acpi_status status = AE_NOT_FOUND;
+ struct acpi_table_desc *table_desc;
/* Parameter validation */
@@ -309,13 +314,22 @@ acpi_get_table_with_size(char *signature,
return (AE_BAD_PARAMETER);
}
+ /*
+ * Note that the following line is required by some OSPMs, they only
+ * check if the returned table is NULL instead of the returned status
+ * to determined if this function is succeeded.
+ */
+ *out_table = NULL;
+
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
/* Walk the root table list */
for (i = 0, j = 0; i < acpi_gbl_root_table_list.current_table_count;
i++) {
- if (!ACPI_COMPARE_NAME
- (&(acpi_gbl_root_table_list.tables[i].signature),
- signature)) {
+ table_desc = &acpi_gbl_root_table_list.tables[i];
+
+ if (!ACPI_COMPARE_NAME(&table_desc->signature, signature)) {
continue;
}
@@ -323,43 +337,65 @@ acpi_get_table_with_size(char *signature,
continue;
}
- status =
- acpi_tb_validate_table(&acpi_gbl_root_table_list.tables[i]);
- if (ACPI_SUCCESS(status)) {
- *out_table = acpi_gbl_root_table_list.tables[i].pointer;
- *tbl_size = acpi_gbl_root_table_list.tables[i].length;
- }
-
- if (!acpi_gbl_permanent_mmap) {
- acpi_gbl_root_table_list.tables[i].pointer = NULL;
- }
-
- return (status);
+ status = acpi_tb_get_table(table_desc, out_table);
+ break;
}
- return (AE_NOT_FOUND);
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return (status);
}
-ACPI_EXPORT_SYMBOL(acpi_get_table_with_size)
+ACPI_EXPORT_SYMBOL(acpi_get_table)
-acpi_status
-acpi_get_table(char *signature,
- u32 instance, struct acpi_table_header **out_table)
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_put_table
+ *
+ * PARAMETERS: table - The pointer to the table
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Release a table returned by acpi_get_table() and its clones.
+ * Note that it is not safe if this function was invoked after an
+ * uninstallation happened to the original table descriptor.
+ * Currently there is no OSPMs' requirement to handle such
+ * situations.
+ *
+ ******************************************************************************/
+void acpi_put_table(struct acpi_table_header *table)
{
- acpi_size tbl_size;
+ u32 i;
+ struct acpi_table_desc *table_desc;
+
+ ACPI_FUNCTION_TRACE(acpi_put_table);
+
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+ /* Walk the root table list */
+
+ for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) {
+ table_desc = &acpi_gbl_root_table_list.tables[i];
- return acpi_get_table_with_size(signature,
- instance, out_table, &tbl_size);
+ if (table_desc->pointer != table) {
+ continue;
+ }
+
+ acpi_tb_put_table(table_desc);
+ break;
+ }
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_VOID;
}
-ACPI_EXPORT_SYMBOL(acpi_get_table)
+ACPI_EXPORT_SYMBOL(acpi_put_table)
/*******************************************************************************
*
* FUNCTION: acpi_get_table_by_index
*
* PARAMETERS: table_index - Table index
- * table - Where the pointer to the table is returned
+ * out_table - Where the pointer to the table is returned
*
* RETURN: Status and pointer to the requested table
*
@@ -368,7 +404,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_table)
*
******************************************************************************/
acpi_status
-acpi_get_table_by_index(u32 table_index, struct acpi_table_header **table)
+acpi_get_table_by_index(u32 table_index, struct acpi_table_header **out_table)
{
acpi_status status;
@@ -376,35 +412,33 @@ acpi_get_table_by_index(u32 table_index, struct acpi_table_header **table)
/* Parameter validation */
- if (!table) {
+ if (!out_table) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
+ /*
+ * Note that the following line is required by some OSPMs, they only
+ * check if the returned table is NULL instead of the returned status
+ * to determined if this function is succeeded.
+ */
+ *out_table = NULL;
+
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
/* Validate index */
if (table_index >= acpi_gbl_root_table_list.current_table_count) {
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
}
- if (!acpi_gbl_root_table_list.tables[table_index].pointer) {
-
- /* Table is not mapped, map it */
+ status =
+ acpi_tb_get_table(&acpi_gbl_root_table_list.tables[table_index],
+ out_table);
- status =
- acpi_tb_validate_table(&acpi_gbl_root_table_list.
- tables[table_index]);
- if (ACPI_FAILURE(status)) {
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- return_ACPI_STATUS(status);
- }
- }
-
- *table = acpi_gbl_root_table_list.tables[table_index].pointer;
+unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- return_ACPI_STATUS(AE_OK);
+ return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_get_table_by_index)
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 5cbefd7621f0..95855cb9d6fb 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -974,7 +974,7 @@ void __init acpi_early_init(void)
if (!acpi_strict)
acpi_gbl_enable_interpreter_slack = TRUE;
- acpi_gbl_permanent_mmap = 1;
+ acpi_permanent_mmap = true;
/*
* If the machine falls into the DMI check table,
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 312c4b4dc363..2f82b8eba360 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -2806,12 +2806,13 @@ static int acpi_nfit_add(struct acpi_device *adev)
acpi_size sz;
int rc = 0;
- status = acpi_get_table_with_size(ACPI_SIG_NFIT, 0, &tbl, &sz);
+ status = acpi_get_table(ACPI_SIG_NFIT, 0, &tbl);
if (ACPI_FAILURE(status)) {
/* This is ok, we could have an nvdimm hotplugged later */
dev_dbg(dev, "failed to find NFIT at startup\n");
return 0;
}
+ sz = tbl->length;
acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL);
if (!acpi_desc)
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index ce3a7a16f03f..edb0c79f7c64 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -70,7 +70,7 @@ int acpi_map_pxm_to_node(int pxm)
{
int node;
- if (pxm < 0 || pxm >= MAX_PXM_DOMAINS)
+ if (pxm < 0 || pxm >= MAX_PXM_DOMAINS || numa_off)
return NUMA_NO_NODE;
node = pxm_to_node_map[pxm];
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 9a4c6abee63e..a404ff4d7151 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -76,6 +76,7 @@ static struct workqueue_struct *kacpi_notify_wq;
static struct workqueue_struct *kacpi_hotplug_wq;
static bool acpi_os_initialized;
unsigned int acpi_sci_irq = INVALID_ACPI_IRQ;
+bool acpi_permanent_mmap = false;
/*
* This list of permanent mappings is for memory that may be accessed from
@@ -306,7 +307,7 @@ static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr)
* virtual address). If not found, map it, add it to that list and return a
* pointer to it.
*
- * During early init (when acpi_gbl_permanent_mmap has not been set yet) this
+ * During early init (when acpi_permanent_mmap has not been set yet) this
* routine simply calls __acpi_map_table() to get the job done.
*/
void __iomem *__ref
@@ -322,7 +323,7 @@ acpi_os_map_iomem(acpi_physical_address phys, acpi_size size)
return NULL;
}
- if (!acpi_gbl_permanent_mmap)
+ if (!acpi_permanent_mmap)
return __acpi_map_table((unsigned long)phys, size);
mutex_lock(&acpi_ioremap_lock);
@@ -392,7 +393,7 @@ static void acpi_os_map_cleanup(struct acpi_ioremap *map)
* mappings, drop a reference to it and unmap it if there are no more active
* references to it.
*
- * During early init (when acpi_gbl_permanent_mmap has not been set yet) this
+ * During early init (when acpi_permanent_mmap has not been set yet) this
* routine simply calls __acpi_unmap_table() to get the job done. Since
* __acpi_unmap_table() is an __init function, the __ref annotation is needed
* here.
@@ -401,7 +402,7 @@ void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size)
{
struct acpi_ioremap *map;
- if (!acpi_gbl_permanent_mmap) {
+ if (!acpi_permanent_mmap) {
__acpi_unmap_table(virt, size);
return;
}
@@ -426,12 +427,6 @@ void __ref acpi_os_unmap_memory(void *virt, acpi_size size)
}
EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
-void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
-{
- if (!acpi_gbl_permanent_mmap)
- __acpi_unmap_table(virt, size);
-}
-
int acpi_os_map_generic_address(struct acpi_generic_address *gas)
{
u64 addr;
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 5c78ee1860b0..611a5585a902 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -154,18 +154,16 @@ static phys_cpuid_t map_madt_entry(struct acpi_table_madt *madt,
phys_cpuid_t __init acpi_map_madt_entry(u32 acpi_id)
{
struct acpi_table_madt *madt = NULL;
- acpi_size tbl_size;
phys_cpuid_t rv;
- acpi_get_table_with_size(ACPI_SIG_MADT, 0,
- (struct acpi_table_header **)&madt,
- &tbl_size);
+ acpi_get_table(ACPI_SIG_MADT, 0,
+ (struct acpi_table_header **)&madt);
if (!madt)
return PHYS_CPUID_INVALID;
rv = map_madt_entry(madt, 1, acpi_id, true);
- early_acpi_os_unmap_memory(madt, tbl_size);
+ acpi_put_table((struct acpi_table_header *)madt);
return rv;
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 93b00cf4eb39..45dec874ea55 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1120,9 +1120,6 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight "
"support\n"));
*cap |= ACPI_VIDEO_BACKLIGHT;
- if (!acpi_has_method(handle, "_BQC"))
- printk(KERN_WARNING FW_BUG PREFIX "No _BQC method, "
- "cannot determine initial brightness\n");
/* We have backlight support, no need to scan further */
return AE_CTRL_TERMINATE;
}
diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c
index e8d7bc7d4da8..b8019c4c1d38 100644
--- a/drivers/acpi/spcr.c
+++ b/drivers/acpi/spcr.c
@@ -33,7 +33,6 @@ int __init parse_spcr(bool earlycon)
{
static char opts[64];
struct acpi_table_spcr *table;
- acpi_size table_size;
acpi_status status;
char *uart;
char *iotype;
@@ -43,9 +42,8 @@ int __init parse_spcr(bool earlycon)
if (acpi_disabled)
return -ENODEV;
- status = acpi_get_table_with_size(ACPI_SIG_SPCR, 0,
- (struct acpi_table_header **)&table,
- &table_size);
+ status = acpi_get_table(ACPI_SIG_SPCR, 0,
+ (struct acpi_table_header **)&table);
if (ACPI_FAILURE(status))
return -ENOENT;
@@ -106,6 +104,6 @@ int __init parse_spcr(bool earlycon)
err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
done:
- early_acpi_os_unmap_memory((void __iomem *)table, table_size);
+ acpi_put_table((struct acpi_table_header *)table);
return err;
}
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index cdd56c4657e0..2604189d6cd1 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -333,7 +333,6 @@ acpi_table_parse_entries_array(char *id,
unsigned int max_entries)
{
struct acpi_table_header *table_header = NULL;
- acpi_size tbl_size;
int count;
u32 instance = 0;
@@ -346,7 +345,7 @@ acpi_table_parse_entries_array(char *id,
if (!strncmp(id, ACPI_SIG_MADT, 4))
instance = acpi_apic_instance;
- acpi_get_table_with_size(id, instance, &table_header, &tbl_size);
+ acpi_get_table(id, instance, &table_header);
if (!table_header) {
pr_warn("%4.4s not present\n", id);
return -ENODEV;
@@ -355,7 +354,7 @@ acpi_table_parse_entries_array(char *id,
count = acpi_parse_entries_array(id, table_size, table_header,
proc, proc_num, max_entries);
- early_acpi_os_unmap_memory((char *)table_header, tbl_size);
+ acpi_put_table(table_header);
return count;
}
@@ -397,7 +396,6 @@ acpi_table_parse_madt(enum acpi_madt_type id,
int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler)
{
struct acpi_table_header *table = NULL;
- acpi_size tbl_size;
if (acpi_disabled)
return -ENODEV;
@@ -406,13 +404,13 @@ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler)
return -EINVAL;
if (strncmp(id, ACPI_SIG_MADT, 4) == 0)
- acpi_get_table_with_size(id, acpi_apic_instance, &table, &tbl_size);
+ acpi_get_table(id, acpi_apic_instance, &table);
else
- acpi_get_table_with_size(id, 0, &table, &tbl_size);
+ acpi_get_table(id, 0, &table);
if (table) {
handler(table);
- early_acpi_os_unmap_memory(table, tbl_size);
+ acpi_put_table(table);
return 0;
} else
return -ENODEV;
@@ -426,16 +424,15 @@ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler)
static void __init check_multiple_madt(void)
{
struct acpi_table_header *table = NULL;
- acpi_size tbl_size;
- acpi_get_table_with_size(ACPI_SIG_MADT, 2, &table, &tbl_size);
+ acpi_get_table(ACPI_SIG_MADT, 2, &table);
if (table) {
pr_warn("BIOS bug: multiple APIC/MADT found, using %d\n",
acpi_apic_instance);
pr_warn("If \"acpi_apic_instance=%d\" works better, "
"notify linux-acpi@vger.kernel.org\n",
acpi_apic_instance ? 0 : 2);
- early_acpi_os_unmap_memory(table, tbl_size);
+ acpi_put_table(table);
} else
acpi_apic_instance = 0;
diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c
index 1e3903d0d994..eb3af2739537 100644
--- a/drivers/base/cacheinfo.c
+++ b/drivers/base/cacheinfo.c
@@ -363,6 +363,7 @@ static ssize_t file_name##_show(struct device *dev, \
return sprintf(buf, "%u\n", this_leaf->object); \
}
+show_one(id, id);
show_one(level, level);
show_one(coherency_line_size, coherency_line_size);
show_one(number_of_sets, number_of_sets);
@@ -444,6 +445,7 @@ static ssize_t write_policy_show(struct device *dev,
return n;
}
+static DEVICE_ATTR_RO(id);
static DEVICE_ATTR_RO(level);
static DEVICE_ATTR_RO(type);
static DEVICE_ATTR_RO(coherency_line_size);
@@ -457,6 +459,7 @@ static DEVICE_ATTR_RO(shared_cpu_list);
static DEVICE_ATTR_RO(physical_line_partition);
static struct attribute *cache_default_attrs[] = {
+ &dev_attr_id.attr,
&dev_attr_type.attr,
&dev_attr_level.attr,
&dev_attr_shared_cpu_map.attr,
@@ -480,6 +483,8 @@ cache_default_attrs_is_visible(struct kobject *kobj,
const struct cpumask *mask = &this_leaf->shared_cpu_map;
umode_t mode = attr->mode;
+ if ((attr == &dev_attr_id.attr) && (this_leaf->attributes & CACHE_ID))
+ return mode;
if ((attr == &dev_attr_type.attr) && this_leaf->type)
return mode;
if ((attr == &dev_attr_level.attr) && this_leaf->level)
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 3a98702b7445..3a2ca0f79daf 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -930,7 +930,7 @@ static void __init acpi_cpufreq_boost_init(void)
static void acpi_cpufreq_boost_exit(void)
{
- if (acpi_cpufreq_online >= 0)
+ if (acpi_cpufreq_online > 0)
cpuhp_remove_state_nocalls(acpi_cpufreq_online);
}
diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c
index 176e84cc3991..0cb9040eca49 100644
--- a/drivers/cpufreq/s3c64xx-cpufreq.c
+++ b/drivers/cpufreq/s3c64xx-cpufreq.c
@@ -107,7 +107,7 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
}
#ifdef CONFIG_REGULATOR
-static void __init s3c64xx_cpufreq_config_regulator(void)
+static void s3c64xx_cpufreq_config_regulator(void)
{
int count, v, i, found;
struct cpufreq_frequency_table *freq;
diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c
index 26ec39ddf21f..ed758b74ddf0 100644
--- a/drivers/dax/dax.c
+++ b/drivers/dax/dax.c
@@ -75,6 +75,73 @@ struct dax_dev {
struct resource res[0];
};
+static ssize_t id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dax_region *dax_region;
+ ssize_t rc = -ENXIO;
+
+ device_lock(dev);
+ dax_region = dev_get_drvdata(dev);
+ if (dax_region)
+ rc = sprintf(buf, "%d\n", dax_region->id);
+ device_unlock(dev);
+
+ return rc;
+}
+static DEVICE_ATTR_RO(id);
+
+static ssize_t region_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dax_region *dax_region;
+ ssize_t rc = -ENXIO;
+
+ device_lock(dev);
+ dax_region = dev_get_drvdata(dev);
+ if (dax_region)
+ rc = sprintf(buf, "%llu\n", (unsigned long long)
+ resource_size(&dax_region->res));
+ device_unlock(dev);
+
+ return rc;
+}
+static struct device_attribute dev_attr_region_size = __ATTR(size, 0444,
+ region_size_show, NULL);
+
+static ssize_t align_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dax_region *dax_region;
+ ssize_t rc = -ENXIO;
+
+ device_lock(dev);
+ dax_region = dev_get_drvdata(dev);
+ if (dax_region)
+ rc = sprintf(buf, "%u\n", dax_region->align);
+ device_unlock(dev);
+
+ return rc;
+}
+static DEVICE_ATTR_RO(align);
+
+static struct attribute *dax_region_attributes[] = {
+ &dev_attr_region_size.attr,
+ &dev_attr_align.attr,
+ &dev_attr_id.attr,
+ NULL,
+};
+
+static const struct attribute_group dax_region_attribute_group = {
+ .name = "dax_region",
+ .attrs = dax_region_attributes,
+};
+
+static const struct attribute_group *dax_region_attribute_groups[] = {
+ &dax_region_attribute_group,
+ NULL,
+};
+
static struct inode *dax_alloc_inode(struct super_block *sb)
{
return kmem_cache_alloc(dax_cache, GFP_KERNEL);
@@ -200,12 +267,31 @@ void dax_region_put(struct dax_region *dax_region)
}
EXPORT_SYMBOL_GPL(dax_region_put);
+static void dax_region_unregister(void *region)
+{
+ struct dax_region *dax_region = region;
+
+ sysfs_remove_groups(&dax_region->dev->kobj,
+ dax_region_attribute_groups);
+ dax_region_put(dax_region);
+}
+
struct dax_region *alloc_dax_region(struct device *parent, int region_id,
struct resource *res, unsigned int align, void *addr,
unsigned long pfn_flags)
{
struct dax_region *dax_region;
+ /*
+ * The DAX core assumes that it can store its private data in
+ * parent->driver_data. This WARN is a reminder / safeguard for
+ * developers of device-dax drivers.
+ */
+ if (dev_get_drvdata(parent)) {
+ dev_WARN(parent, "dax core failed to setup private data\n");
+ return NULL;
+ }
+
if (!IS_ALIGNED(res->start, align)
|| !IS_ALIGNED(resource_size(res), align))
return NULL;
@@ -214,6 +300,7 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id,
if (!dax_region)
return NULL;
+ dev_set_drvdata(parent, dax_region);
memcpy(&dax_region->res, res, sizeof(*res));
dax_region->pfn_flags = pfn_flags;
kref_init(&dax_region->kref);
@@ -222,7 +309,14 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id,
dax_region->align = align;
dax_region->dev = parent;
dax_region->base = addr;
+ if (sysfs_create_groups(&parent->kobj, dax_region_attribute_groups)) {
+ kfree(dax_region);
+ return NULL;;
+ }
+ kref_get(&dax_region->kref);
+ if (devm_add_action_or_reset(parent, dax_region_unregister, dax_region))
+ return NULL;
return dax_region;
}
EXPORT_SYMBOL_GPL(alloc_dax_region);
diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c
index 73c6ce93a0d9..033f49b31fdc 100644
--- a/drivers/dax/pmem.c
+++ b/drivers/dax/pmem.c
@@ -89,7 +89,8 @@ static int dax_pmem_probe(struct device *dev)
pfn_sb = nd_pfn->pfn_sb;
if (!devm_request_mem_region(dev, nsio->res.start,
- resource_size(&nsio->res), dev_name(dev))) {
+ resource_size(&nsio->res),
+ dev_name(&ndns->dev))) {
dev_warn(dev, "could not reserve region %pR\n", &nsio->res);
return -EBUSY;
}
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 88bebe1968b7..54be60ead08f 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -560,7 +560,7 @@ static int __init dmi_present(const u8 *buf)
dmi_ver >> 16, (dmi_ver >> 8) & 0xFF);
}
dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string));
- printk(KERN_DEBUG "DMI: %s\n", dmi_ids_string);
+ pr_info("DMI: %s\n", dmi_ids_string);
return 0;
}
}
@@ -588,7 +588,7 @@ static int __init dmi_smbios3_present(const u8 *buf)
dmi_ver >> 16, (dmi_ver >> 8) & 0xFF,
dmi_ver & 0xFF);
dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string));
- pr_debug("DMI: %s\n", dmi_ids_string);
+ pr_info("DMI: %s\n", dmi_ids_string);
return 0;
}
}
diff --git a/drivers/gpio/gpio-tps65218.c b/drivers/gpio/gpio-tps65218.c
index d779307a9685..46e6dcc089cb 100644
--- a/drivers/gpio/gpio-tps65218.c
+++ b/drivers/gpio/gpio-tps65218.c
@@ -16,6 +16,7 @@
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/mfd/tps65218.h>
struct tps65218_gpio {
@@ -30,7 +31,7 @@ static int tps65218_gpio_get(struct gpio_chip *gc, unsigned offset)
unsigned int val;
int ret;
- ret = tps65218_reg_read(tps65218, TPS65218_REG_ENABLE2, &val);
+ ret = regmap_read(tps65218->regmap, TPS65218_REG_ENABLE2, &val);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
index 4f973a9c7b87..8ec1967a850b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
@@ -305,8 +305,9 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
GOP_VBIOS_CONTENT *vbios;
VFCT_IMAGE_HEADER *vhdr;
- if (!ACPI_SUCCESS(acpi_get_table_with_size("VFCT", 1, &hdr, &tbl_size)))
+ if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
return false;
+ tbl_size = hdr->length;
if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n");
goto out_unmap;
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index 5ddde7349fbd..183f5dc1c3f2 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -116,6 +116,7 @@ config DRM_I915_GVT_KVMGT
tristate "Enable KVM/VFIO support for Intel GVT-g"
depends on DRM_I915_GVT
depends on KVM
+ depends on VFIO_MDEV && VFIO_MDEV_DEVICE
default n
help
Choose this option if you want to enable KVMGT support for
diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index 8a46a7f31d53..b123c20e2097 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -5,6 +5,4 @@ GVT_SOURCE := gvt.o aperture_gm.o handlers.o vgpu.o trace_points.o firmware.o \
ccflags-y += -I$(src) -I$(src)/$(GVT_DIR) -Wall
i915-y += $(addprefix $(GVT_DIR)/, $(GVT_SOURCE))
-
-CFLAGS_kvmgt.o := -Wno-unused-function
obj-$(CONFIG_DRM_I915_GVT_KVMGT) += $(GVT_DIR)/kvmgt.o
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index b1a7c8dd4b5f..ad0e9364ee70 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -164,15 +164,17 @@ struct intel_vgpu {
#if IS_ENABLED(CONFIG_DRM_I915_GVT_KVMGT)
struct {
- struct device *mdev;
+ struct mdev_device *mdev;
struct vfio_region *region;
int num_regions;
struct eventfd_ctx *intx_trigger;
struct eventfd_ctx *msi_trigger;
struct rb_root cache;
struct mutex cache_lock;
- void *vfio_group;
struct notifier_block iommu_notifier;
+ struct notifier_block group_notifier;
+ struct kvm *kvm;
+ struct work_struct release_work;
} vdev;
#endif
};
diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c
index dc0365033157..4dd6722a7339 100644
--- a/drivers/gpu/drm/i915/gvt/kvmgt.c
+++ b/drivers/gpu/drm/i915/gvt/kvmgt.c
@@ -31,6 +31,7 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/mm.h>
+#include <linux/mmu_context.h>
#include <linux/types.h>
#include <linux/list.h>
#include <linux/rbtree.h>
@@ -39,24 +40,13 @@
#include <linux/uuid.h>
#include <linux/kvm_host.h>
#include <linux/vfio.h>
+#include <linux/mdev.h>
#include "i915_drv.h"
#include "gvt.h"
-static inline long kvmgt_pin_pages(struct device *dev, unsigned long *user_pfn,
- long npage, int prot, unsigned long *phys_pfn)
-{
- return 0;
-}
-static inline long kvmgt_unpin_pages(struct device *dev, unsigned long *pfn,
- long npage)
-{
- return 0;
-}
-
static const struct intel_gvt_ops *intel_gvt_ops;
-
/* helper macros copied from vfio-pci */
#define VFIO_PCI_OFFSET_SHIFT 40
#define VFIO_PCI_OFFSET_TO_INDEX(off) (off >> VFIO_PCI_OFFSET_SHIFT)
@@ -90,6 +80,15 @@ struct gvt_dma {
kvm_pfn_t pfn;
};
+static inline bool handle_valid(unsigned long handle)
+{
+ return !!(handle & ~0xff);
+}
+
+static int kvmgt_guest_init(struct mdev_device *mdev);
+static void intel_vgpu_release_work(struct work_struct *work);
+static bool kvmgt_guest_exit(struct kvmgt_guest_info *info);
+
static struct gvt_dma *__gvt_cache_find(struct intel_vgpu *vgpu, gfn_t gfn)
{
struct rb_node *node = vgpu->vdev.cache.rb_node;
@@ -167,9 +166,10 @@ static void __gvt_cache_remove_entry(struct intel_vgpu *vgpu,
static void gvt_cache_remove(struct intel_vgpu *vgpu, gfn_t gfn)
{
- struct device *dev = vgpu->vdev.mdev;
+ struct device *dev = &vgpu->vdev.mdev->dev;
struct gvt_dma *this;
- unsigned long pfn;
+ unsigned long g1;
+ int rc;
mutex_lock(&vgpu->vdev.cache_lock);
this = __gvt_cache_find(vgpu, gfn);
@@ -178,8 +178,9 @@ static void gvt_cache_remove(struct intel_vgpu *vgpu, gfn_t gfn)
return;
}
- pfn = this->pfn;
- WARN_ON((kvmgt_unpin_pages(dev, &pfn, 1) != 1));
+ g1 = gfn;
+ rc = vfio_unpin_pages(dev, &g1, 1);
+ WARN_ON(rc != 1);
__gvt_cache_remove_entry(vgpu, this);
mutex_unlock(&vgpu->vdev.cache_lock);
}
@@ -194,15 +195,15 @@ static void gvt_cache_destroy(struct intel_vgpu *vgpu)
{
struct gvt_dma *dma;
struct rb_node *node = NULL;
- struct device *dev = vgpu->vdev.mdev;
- unsigned long pfn;
+ struct device *dev = &vgpu->vdev.mdev->dev;
+ unsigned long gfn;
mutex_lock(&vgpu->vdev.cache_lock);
while ((node = rb_first(&vgpu->vdev.cache))) {
dma = rb_entry(node, struct gvt_dma, node);
- pfn = dma->pfn;
+ gfn = dma->gfn;
- kvmgt_unpin_pages(dev, &pfn, 1);
+ vfio_unpin_pages(dev, &gfn, 1);
__gvt_cache_remove_entry(vgpu, dma);
}
mutex_unlock(&vgpu->vdev.cache_lock);
@@ -226,7 +227,53 @@ static struct intel_vgpu_type *intel_gvt_find_vgpu_type(struct intel_gvt *gvt,
return NULL;
}
+static ssize_t available_instance_show(struct kobject *kobj, struct device *dev,
+ char *buf)
+{
+ struct intel_vgpu_type *type;
+ unsigned int num = 0;
+ void *gvt = kdev_to_i915(dev)->gvt;
+
+ type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj));
+ if (!type)
+ num = 0;
+ else
+ num = type->avail_instance;
+
+ return sprintf(buf, "%u\n", num);
+}
+
+static ssize_t device_api_show(struct kobject *kobj, struct device *dev,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", VFIO_DEVICE_API_PCI_STRING);
+}
+
+static ssize_t description_show(struct kobject *kobj, struct device *dev,
+ char *buf)
+{
+ struct intel_vgpu_type *type;
+ void *gvt = kdev_to_i915(dev)->gvt;
+
+ type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj));
+ if (!type)
+ return 0;
+
+ return sprintf(buf, "low_gm_size: %dMB\nhigh_gm_size: %dMB\n"
+ "fence: %d\n",
+ BYTES_TO_MB(type->low_gm_size),
+ BYTES_TO_MB(type->high_gm_size),
+ type->fence);
+}
+
+static MDEV_TYPE_ATTR_RO(available_instance);
+static MDEV_TYPE_ATTR_RO(device_api);
+static MDEV_TYPE_ATTR_RO(description);
+
static struct attribute *type_attrs[] = {
+ &mdev_type_attr_available_instance.attr,
+ &mdev_type_attr_device_api.attr,
+ &mdev_type_attr_description.attr,
NULL,
};
@@ -322,7 +369,7 @@ static void kvmgt_protect_table_add(struct kvmgt_guest_info *info, gfn_t gfn)
if (kvmgt_gfn_is_write_protected(info, gfn))
return;
- p = kmalloc(sizeof(struct kvmgt_pgfn), GFP_ATOMIC);
+ p = kzalloc(sizeof(struct kvmgt_pgfn), GFP_ATOMIC);
if (WARN(!p, "gfn: 0x%llx\n", gfn))
return;
@@ -342,6 +389,720 @@ static void kvmgt_protect_table_del(struct kvmgt_guest_info *info,
}
}
+static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev)
+{
+ struct intel_vgpu *vgpu;
+ struct intel_vgpu_type *type;
+ struct device *pdev;
+ void *gvt;
+
+ pdev = mdev->parent->dev;
+ gvt = kdev_to_i915(pdev)->gvt;
+
+ type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj));
+ if (!type) {
+ gvt_err("failed to find type %s to create\n",
+ kobject_name(kobj));
+ return -EINVAL;
+ }
+
+ vgpu = intel_gvt_ops->vgpu_create(gvt, type);
+ if (IS_ERR_OR_NULL(vgpu)) {
+ gvt_err("create intel vgpu failed\n");
+ return -EINVAL;
+ }
+
+ INIT_WORK(&vgpu->vdev.release_work, intel_vgpu_release_work);
+
+ vgpu->vdev.mdev = mdev;
+ mdev_set_drvdata(mdev, vgpu);
+
+ gvt_dbg_core("intel_vgpu_create succeeded for mdev: %s\n",
+ dev_name(&mdev->dev));
+ return 0;
+}
+
+static int intel_vgpu_remove(struct mdev_device *mdev)
+{
+ struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
+
+ if (handle_valid(vgpu->handle))
+ return -EBUSY;
+
+ intel_gvt_ops->vgpu_destroy(vgpu);
+ return 0;
+}
+
+static int intel_vgpu_iommu_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct intel_vgpu *vgpu = container_of(nb,
+ struct intel_vgpu,
+ vdev.iommu_notifier);
+
+ if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) {
+ struct vfio_iommu_type1_dma_unmap *unmap = data;
+ unsigned long gfn, end_gfn;
+
+ gfn = unmap->iova >> PAGE_SHIFT;
+ end_gfn = gfn + unmap->size / PAGE_SIZE;
+
+ while (gfn < end_gfn)
+ gvt_cache_remove(vgpu, gfn++);
+ }
+
+ return NOTIFY_OK;
+}
+
+static int intel_vgpu_group_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct intel_vgpu *vgpu = container_of(nb,
+ struct intel_vgpu,
+ vdev.group_notifier);
+
+ /* the only action we care about */
+ if (action == VFIO_GROUP_NOTIFY_SET_KVM) {
+ vgpu->vdev.kvm = data;
+
+ if (!data)
+ schedule_work(&vgpu->vdev.release_work);
+ }
+
+ return NOTIFY_OK;
+}
+
+static int intel_vgpu_open(struct mdev_device *mdev)
+{
+ struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
+ unsigned long events;
+ int ret;
+
+ vgpu->vdev.iommu_notifier.notifier_call = intel_vgpu_iommu_notifier;
+ vgpu->vdev.group_notifier.notifier_call = intel_vgpu_group_notifier;
+
+ events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
+ ret = vfio_register_notifier(&mdev->dev, VFIO_IOMMU_NOTIFY, &events,
+ &vgpu->vdev.iommu_notifier);
+ if (ret != 0) {
+ gvt_err("vfio_register_notifier for iommu failed: %d\n", ret);
+ goto out;
+ }
+
+ events = VFIO_GROUP_NOTIFY_SET_KVM;
+ ret = vfio_register_notifier(&mdev->dev, VFIO_GROUP_NOTIFY, &events,
+ &vgpu->vdev.group_notifier);
+ if (ret != 0) {
+ gvt_err("vfio_register_notifier for group failed: %d\n", ret);
+ goto undo_iommu;
+ }
+
+ return kvmgt_guest_init(mdev);
+
+undo_iommu:
+ vfio_unregister_notifier(&mdev->dev, VFIO_IOMMU_NOTIFY,
+ &vgpu->vdev.iommu_notifier);
+out:
+ return ret;
+}
+
+static void __intel_vgpu_release(struct intel_vgpu *vgpu)
+{
+ struct kvmgt_guest_info *info;
+
+ if (!handle_valid(vgpu->handle))
+ return;
+
+ vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_IOMMU_NOTIFY,
+ &vgpu->vdev.iommu_notifier);
+ vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_GROUP_NOTIFY,
+ &vgpu->vdev.group_notifier);
+
+ info = (struct kvmgt_guest_info *)vgpu->handle;
+ kvmgt_guest_exit(info);
+ vgpu->handle = 0;
+}
+
+static void intel_vgpu_release(struct mdev_device *mdev)
+{
+ struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
+
+ __intel_vgpu_release(vgpu);
+}
+
+static void intel_vgpu_release_work(struct work_struct *work)
+{
+ struct intel_vgpu *vgpu = container_of(work, struct intel_vgpu,
+ vdev.release_work);
+ __intel_vgpu_release(vgpu);
+}
+
+static uint64_t intel_vgpu_get_bar0_addr(struct intel_vgpu *vgpu)
+{
+ u32 start_lo, start_hi;
+ u32 mem_type;
+ int pos = PCI_BASE_ADDRESS_0;
+
+ start_lo = (*(u32 *)(vgpu->cfg_space.virtual_cfg_space + pos)) &
+ PCI_BASE_ADDRESS_MEM_MASK;
+ mem_type = (*(u32 *)(vgpu->cfg_space.virtual_cfg_space + pos)) &
+ PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+
+ switch (mem_type) {
+ case PCI_BASE_ADDRESS_MEM_TYPE_64:
+ start_hi = (*(u32 *)(vgpu->cfg_space.virtual_cfg_space
+ + pos + 4));
+ break;
+ case PCI_BASE_ADDRESS_MEM_TYPE_32:
+ case PCI_BASE_ADDRESS_MEM_TYPE_1M:
+ /* 1M mem BAR treated as 32-bit BAR */
+ default:
+ /* mem unknown type treated as 32-bit BAR */
+ start_hi = 0;
+ break;
+ }
+
+ return ((u64)start_hi << 32) | start_lo;
+}
+
+static ssize_t intel_vgpu_rw(struct mdev_device *mdev, char *buf,
+ size_t count, loff_t *ppos, bool is_write)
+{
+ struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
+ unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
+ uint64_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
+ int ret = -EINVAL;
+
+
+ if (index >= VFIO_PCI_NUM_REGIONS) {
+ gvt_err("invalid index: %u\n", index);
+ return -EINVAL;
+ }
+
+ switch (index) {
+ case VFIO_PCI_CONFIG_REGION_INDEX:
+ if (is_write)
+ ret = intel_gvt_ops->emulate_cfg_write(vgpu, pos,
+ buf, count);
+ else
+ ret = intel_gvt_ops->emulate_cfg_read(vgpu, pos,
+ buf, count);
+ break;
+ case VFIO_PCI_BAR0_REGION_INDEX:
+ case VFIO_PCI_BAR1_REGION_INDEX:
+ if (is_write) {
+ uint64_t bar0_start = intel_vgpu_get_bar0_addr(vgpu);
+
+ ret = intel_gvt_ops->emulate_mmio_write(vgpu,
+ bar0_start + pos, buf, count);
+ } else {
+ uint64_t bar0_start = intel_vgpu_get_bar0_addr(vgpu);
+
+ ret = intel_gvt_ops->emulate_mmio_read(vgpu,
+ bar0_start + pos, buf, count);
+ }
+ break;
+ case VFIO_PCI_BAR2_REGION_INDEX:
+ case VFIO_PCI_BAR3_REGION_INDEX:
+ case VFIO_PCI_BAR4_REGION_INDEX:
+ case VFIO_PCI_BAR5_REGION_INDEX:
+ case VFIO_PCI_VGA_REGION_INDEX:
+ case VFIO_PCI_ROM_REGION_INDEX:
+ default:
+ gvt_err("unsupported region: %u\n", index);
+ }
+
+ return ret == 0 ? count : ret;
+}
+
+static ssize_t intel_vgpu_read(struct mdev_device *mdev, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int done = 0;
+ int ret;
+
+ while (count) {
+ size_t filled;
+
+ if (count >= 4 && !(*ppos % 4)) {
+ u32 val;
+
+ ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val),
+ ppos, false);
+ if (ret <= 0)
+ goto read_err;
+
+ if (copy_to_user(buf, &val, sizeof(val)))
+ goto read_err;
+
+ filled = 4;
+ } else if (count >= 2 && !(*ppos % 2)) {
+ u16 val;
+
+ ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val),
+ ppos, false);
+ if (ret <= 0)
+ goto read_err;
+
+ if (copy_to_user(buf, &val, sizeof(val)))
+ goto read_err;
+
+ filled = 2;
+ } else {
+ u8 val;
+
+ ret = intel_vgpu_rw(mdev, &val, sizeof(val), ppos,
+ false);
+ if (ret <= 0)
+ goto read_err;
+
+ if (copy_to_user(buf, &val, sizeof(val)))
+ goto read_err;
+
+ filled = 1;
+ }
+
+ count -= filled;
+ done += filled;
+ *ppos += filled;
+ buf += filled;
+ }
+
+ return done;
+
+read_err:
+ return -EFAULT;
+}
+
+static ssize_t intel_vgpu_write(struct mdev_device *mdev,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int done = 0;
+ int ret;
+
+ while (count) {
+ size_t filled;
+
+ if (count >= 4 && !(*ppos % 4)) {
+ u32 val;
+
+ if (copy_from_user(&val, buf, sizeof(val)))
+ goto write_err;
+
+ ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val),
+ ppos, true);
+ if (ret <= 0)
+ goto write_err;
+
+ filled = 4;
+ } else if (count >= 2 && !(*ppos % 2)) {
+ u16 val;
+
+ if (copy_from_user(&val, buf, sizeof(val)))
+ goto write_err;
+
+ ret = intel_vgpu_rw(mdev, (char *)&val,
+ sizeof(val), ppos, true);
+ if (ret <= 0)
+ goto write_err;
+
+ filled = 2;
+ } else {
+ u8 val;
+
+ if (copy_from_user(&val, buf, sizeof(val)))
+ goto write_err;
+
+ ret = intel_vgpu_rw(mdev, &val, sizeof(val),
+ ppos, true);
+ if (ret <= 0)
+ goto write_err;
+
+ filled = 1;
+ }
+
+ count -= filled;
+ done += filled;
+ *ppos += filled;
+ buf += filled;
+ }
+
+ return done;
+write_err:
+ return -EFAULT;
+}
+
+static int intel_vgpu_mmap(struct mdev_device *mdev, struct vm_area_struct *vma)
+{
+ unsigned int index;
+ u64 virtaddr;
+ unsigned long req_size, pgoff = 0;
+ pgprot_t pg_prot;
+ struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
+
+ index = vma->vm_pgoff >> (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT);
+ if (index >= VFIO_PCI_ROM_REGION_INDEX)
+ return -EINVAL;
+
+ if (vma->vm_end < vma->vm_start)
+ return -EINVAL;
+ if ((vma->vm_flags & VM_SHARED) == 0)
+ return -EINVAL;
+ if (index != VFIO_PCI_BAR2_REGION_INDEX)
+ return -EINVAL;
+
+ pg_prot = vma->vm_page_prot;
+ virtaddr = vma->vm_start;
+ req_size = vma->vm_end - vma->vm_start;
+ pgoff = vgpu_aperture_pa_base(vgpu) >> PAGE_SHIFT;
+
+ return remap_pfn_range(vma, virtaddr, pgoff, req_size, pg_prot);
+}
+
+static int intel_vgpu_get_irq_count(struct intel_vgpu *vgpu, int type)
+{
+ if (type == VFIO_PCI_INTX_IRQ_INDEX || type == VFIO_PCI_MSI_IRQ_INDEX)
+ return 1;
+
+ return 0;
+}
+
+static int intel_vgpu_set_intx_mask(struct intel_vgpu *vgpu,
+ unsigned int index, unsigned int start,
+ unsigned int count, uint32_t flags,
+ void *data)
+{
+ return 0;
+}
+
+static int intel_vgpu_set_intx_unmask(struct intel_vgpu *vgpu,
+ unsigned int index, unsigned int start,
+ unsigned int count, uint32_t flags, void *data)
+{
+ return 0;
+}
+
+static int intel_vgpu_set_intx_trigger(struct intel_vgpu *vgpu,
+ unsigned int index, unsigned int start, unsigned int count,
+ uint32_t flags, void *data)
+{
+ return 0;
+}
+
+static int intel_vgpu_set_msi_trigger(struct intel_vgpu *vgpu,
+ unsigned int index, unsigned int start, unsigned int count,
+ uint32_t flags, void *data)
+{
+ struct eventfd_ctx *trigger;
+
+ if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
+ int fd = *(int *)data;
+
+ trigger = eventfd_ctx_fdget(fd);
+ if (IS_ERR(trigger)) {
+ gvt_err("eventfd_ctx_fdget failed\n");
+ return PTR_ERR(trigger);
+ }
+ vgpu->vdev.msi_trigger = trigger;
+ }
+
+ return 0;
+}
+
+static int intel_vgpu_set_irqs(struct intel_vgpu *vgpu, uint32_t flags,
+ unsigned int index, unsigned int start, unsigned int count,
+ void *data)
+{
+ int (*func)(struct intel_vgpu *vgpu, unsigned int index,
+ unsigned int start, unsigned int count, uint32_t flags,
+ void *data) = NULL;
+
+ switch (index) {
+ case VFIO_PCI_INTX_IRQ_INDEX:
+ switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
+ case VFIO_IRQ_SET_ACTION_MASK:
+ func = intel_vgpu_set_intx_mask;
+ break;
+ case VFIO_IRQ_SET_ACTION_UNMASK:
+ func = intel_vgpu_set_intx_unmask;
+ break;
+ case VFIO_IRQ_SET_ACTION_TRIGGER:
+ func = intel_vgpu_set_intx_trigger;
+ break;
+ }
+ break;
+ case VFIO_PCI_MSI_IRQ_INDEX:
+ switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
+ case VFIO_IRQ_SET_ACTION_MASK:
+ case VFIO_IRQ_SET_ACTION_UNMASK:
+ /* XXX Need masking support exported */
+ break;
+ case VFIO_IRQ_SET_ACTION_TRIGGER:
+ func = intel_vgpu_set_msi_trigger;
+ break;
+ }
+ break;
+ }
+
+ if (!func)
+ return -ENOTTY;
+
+ return func(vgpu, index, start, count, flags, data);
+}
+
+static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd,
+ unsigned long arg)
+{
+ struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
+ unsigned long minsz;
+
+ gvt_dbg_core("vgpu%d ioctl, cmd: %d\n", vgpu->id, cmd);
+
+ if (cmd == VFIO_DEVICE_GET_INFO) {
+ struct vfio_device_info info;
+
+ minsz = offsetofend(struct vfio_device_info, num_irqs);
+
+ if (copy_from_user(&info, (void __user *)arg, minsz))
+ return -EFAULT;
+
+ if (info.argsz < minsz)
+ return -EINVAL;
+
+ info.flags = VFIO_DEVICE_FLAGS_PCI;
+ info.flags |= VFIO_DEVICE_FLAGS_RESET;
+ info.num_regions = VFIO_PCI_NUM_REGIONS;
+ info.num_irqs = VFIO_PCI_NUM_IRQS;
+
+ return copy_to_user((void __user *)arg, &info, minsz) ?
+ -EFAULT : 0;
+
+ } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
+ struct vfio_region_info info;
+ struct vfio_info_cap caps = { .buf = NULL, .size = 0 };
+ int i, ret;
+ struct vfio_region_info_cap_sparse_mmap *sparse = NULL;
+ size_t size;
+ int nr_areas = 1;
+ int cap_type_id;
+
+ minsz = offsetofend(struct vfio_region_info, offset);
+
+ if (copy_from_user(&info, (void __user *)arg, minsz))
+ return -EFAULT;
+
+ if (info.argsz < minsz)
+ return -EINVAL;
+
+ switch (info.index) {
+ case VFIO_PCI_CONFIG_REGION_INDEX:
+ info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
+ info.size = INTEL_GVT_MAX_CFG_SPACE_SZ;
+ info.flags = VFIO_REGION_INFO_FLAG_READ |
+ VFIO_REGION_INFO_FLAG_WRITE;
+ break;
+ case VFIO_PCI_BAR0_REGION_INDEX:
+ info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
+ info.size = vgpu->cfg_space.bar[info.index].size;
+ if (!info.size) {
+ info.flags = 0;
+ break;
+ }
+
+ info.flags = VFIO_REGION_INFO_FLAG_READ |
+ VFIO_REGION_INFO_FLAG_WRITE;
+ break;
+ case VFIO_PCI_BAR1_REGION_INDEX:
+ info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
+ info.size = 0;
+ info.flags = 0;
+ break;
+ case VFIO_PCI_BAR2_REGION_INDEX:
+ info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
+ info.flags = VFIO_REGION_INFO_FLAG_CAPS |
+ VFIO_REGION_INFO_FLAG_MMAP |
+ VFIO_REGION_INFO_FLAG_READ |
+ VFIO_REGION_INFO_FLAG_WRITE;
+ info.size = gvt_aperture_sz(vgpu->gvt);
+
+ size = sizeof(*sparse) +
+ (nr_areas * sizeof(*sparse->areas));
+ sparse = kzalloc(size, GFP_KERNEL);
+ if (!sparse)
+ return -ENOMEM;
+
+ sparse->nr_areas = nr_areas;
+ cap_type_id = VFIO_REGION_INFO_CAP_SPARSE_MMAP;
+ sparse->areas[0].offset =
+ PAGE_ALIGN(vgpu_aperture_offset(vgpu));
+ sparse->areas[0].size = vgpu_aperture_sz(vgpu);
+ if (!caps.buf) {
+ kfree(caps.buf);
+ caps.buf = NULL;
+ caps.size = 0;
+ }
+ break;
+
+ case VFIO_PCI_BAR3_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX:
+ info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
+ info.size = 0;
+
+ info.flags = 0;
+ gvt_dbg_core("get region info bar:%d\n", info.index);
+ break;
+
+ case VFIO_PCI_ROM_REGION_INDEX:
+ case VFIO_PCI_VGA_REGION_INDEX:
+ gvt_dbg_core("get region info index:%d\n", info.index);
+ break;
+ default:
+ {
+ struct vfio_region_info_cap_type cap_type;
+
+ if (info.index >= VFIO_PCI_NUM_REGIONS +
+ vgpu->vdev.num_regions)
+ return -EINVAL;
+
+ i = info.index - VFIO_PCI_NUM_REGIONS;
+
+ info.offset =
+ VFIO_PCI_INDEX_TO_OFFSET(info.index);
+ info.size = vgpu->vdev.region[i].size;
+ info.flags = vgpu->vdev.region[i].flags;
+
+ cap_type.type = vgpu->vdev.region[i].type;
+ cap_type.subtype = vgpu->vdev.region[i].subtype;
+
+ ret = vfio_info_add_capability(&caps,
+ VFIO_REGION_INFO_CAP_TYPE,
+ &cap_type);
+ if (ret)
+ return ret;
+ }
+ }
+
+ if ((info.flags & VFIO_REGION_INFO_FLAG_CAPS) && sparse) {
+ switch (cap_type_id) {
+ case VFIO_REGION_INFO_CAP_SPARSE_MMAP:
+ ret = vfio_info_add_capability(&caps,
+ VFIO_REGION_INFO_CAP_SPARSE_MMAP,
+ sparse);
+ kfree(sparse);
+ if (ret)
+ return ret;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ if (caps.size) {
+ if (info.argsz < sizeof(info) + caps.size) {
+ info.argsz = sizeof(info) + caps.size;
+ info.cap_offset = 0;
+ } else {
+ vfio_info_cap_shift(&caps, sizeof(info));
+ if (copy_to_user((void __user *)arg +
+ sizeof(info), caps.buf,
+ caps.size)) {
+ kfree(caps.buf);
+ return -EFAULT;
+ }
+ info.cap_offset = sizeof(info);
+ }
+
+ kfree(caps.buf);
+ }
+
+ return copy_to_user((void __user *)arg, &info, minsz) ?
+ -EFAULT : 0;
+ } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) {
+ struct vfio_irq_info info;
+
+ minsz = offsetofend(struct vfio_irq_info, count);
+
+ if (copy_from_user(&info, (void __user *)arg, minsz))
+ return -EFAULT;
+
+ if (info.argsz < minsz || info.index >= VFIO_PCI_NUM_IRQS)
+ return -EINVAL;
+
+ switch (info.index) {
+ case VFIO_PCI_INTX_IRQ_INDEX:
+ case VFIO_PCI_MSI_IRQ_INDEX:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ info.flags = VFIO_IRQ_INFO_EVENTFD;
+
+ info.count = intel_vgpu_get_irq_count(vgpu, info.index);
+
+ if (info.index == VFIO_PCI_INTX_IRQ_INDEX)
+ info.flags |= (VFIO_IRQ_INFO_MASKABLE |
+ VFIO_IRQ_INFO_AUTOMASKED);
+ else
+ info.flags |= VFIO_IRQ_INFO_NORESIZE;
+
+ return copy_to_user((void __user *)arg, &info, minsz) ?
+ -EFAULT : 0;
+ } else if (cmd == VFIO_DEVICE_SET_IRQS) {
+ struct vfio_irq_set hdr;
+ u8 *data = NULL;
+ int ret = 0;
+ size_t data_size = 0;
+
+ minsz = offsetofend(struct vfio_irq_set, count);
+
+ if (copy_from_user(&hdr, (void __user *)arg, minsz))
+ return -EFAULT;
+
+ if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) {
+ int max = intel_vgpu_get_irq_count(vgpu, hdr.index);
+
+ ret = vfio_set_irqs_validate_and_prepare(&hdr, max,
+ VFIO_PCI_NUM_IRQS, &data_size);
+ if (ret) {
+ gvt_err("intel:vfio_set_irqs_validate_and_prepare failed\n");
+ return -EINVAL;
+ }
+ if (data_size) {
+ data = memdup_user((void __user *)(arg + minsz),
+ data_size);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+ }
+ }
+
+ ret = intel_vgpu_set_irqs(vgpu, hdr.flags, hdr.index,
+ hdr.start, hdr.count, data);
+ kfree(data);
+
+ return ret;
+ } else if (cmd == VFIO_DEVICE_RESET) {
+ intel_gvt_ops->vgpu_reset(vgpu);
+ return 0;
+ }
+
+ return 0;
+}
+
+static const struct parent_ops intel_vgpu_ops = {
+ .supported_type_groups = intel_vgpu_type_groups,
+ .create = intel_vgpu_create,
+ .remove = intel_vgpu_remove,
+
+ .open = intel_vgpu_open,
+ .release = intel_vgpu_release,
+
+ .read = intel_vgpu_read,
+ .write = intel_vgpu_write,
+ .mmap = intel_vgpu_mmap,
+ .ioctl = intel_vgpu_ioctl,
+};
+
static int kvmgt_host_init(struct device *dev, void *gvt, const void *ops)
{
if (!intel_gvt_init_vgpu_type_groups(gvt))
@@ -349,22 +1110,28 @@ static int kvmgt_host_init(struct device *dev, void *gvt, const void *ops)
intel_gvt_ops = ops;
- /* MDEV is not yet available */
- return -ENODEV;
+ return mdev_register_device(dev, &intel_vgpu_ops);
}
static void kvmgt_host_exit(struct device *dev, void *gvt)
{
intel_gvt_cleanup_vgpu_type_groups(gvt);
+ mdev_unregister_device(dev);
}
static int kvmgt_write_protect_add(unsigned long handle, u64 gfn)
{
- struct kvmgt_guest_info *info = (struct kvmgt_guest_info *)handle;
- struct kvm *kvm = info->kvm;
+ struct kvmgt_guest_info *info;
+ struct kvm *kvm;
struct kvm_memory_slot *slot;
int idx;
+ if (!handle_valid(handle))
+ return -ESRCH;
+
+ info = (struct kvmgt_guest_info *)handle;
+ kvm = info->kvm;
+
idx = srcu_read_lock(&kvm->srcu);
slot = gfn_to_memslot(kvm, gfn);
@@ -384,11 +1151,17 @@ out:
static int kvmgt_write_protect_remove(unsigned long handle, u64 gfn)
{
- struct kvmgt_guest_info *info = (struct kvmgt_guest_info *)handle;
- struct kvm *kvm = info->kvm;
+ struct kvmgt_guest_info *info;
+ struct kvm *kvm;
struct kvm_memory_slot *slot;
int idx;
+ if (!handle_valid(handle))
+ return 0;
+
+ info = (struct kvmgt_guest_info *)handle;
+ kvm = info->kvm;
+
idx = srcu_read_lock(&kvm->srcu);
slot = gfn_to_memslot(kvm, gfn);
@@ -476,6 +1249,85 @@ static int kvmgt_detect_host(void)
return kvmgt_check_guest() ? -ENODEV : 0;
}
+static bool __kvmgt_vgpu_exist(struct intel_vgpu *vgpu, struct kvm *kvm)
+{
+ struct intel_vgpu *itr;
+ struct kvmgt_guest_info *info;
+ int id;
+ bool ret = false;
+
+ mutex_lock(&vgpu->gvt->lock);
+ for_each_active_vgpu(vgpu->gvt, itr, id) {
+ if (!handle_valid(itr->handle))
+ continue;
+
+ info = (struct kvmgt_guest_info *)itr->handle;
+ if (kvm && kvm == info->kvm) {
+ ret = true;
+ goto out;
+ }
+ }
+out:
+ mutex_unlock(&vgpu->gvt->lock);
+ return ret;
+}
+
+static int kvmgt_guest_init(struct mdev_device *mdev)
+{
+ struct kvmgt_guest_info *info;
+ struct intel_vgpu *vgpu;
+ struct kvm *kvm;
+
+ vgpu = mdev_get_drvdata(mdev);
+ if (handle_valid(vgpu->handle))
+ return -EEXIST;
+
+ kvm = vgpu->vdev.kvm;
+ if (!kvm || kvm->mm != current->mm) {
+ gvt_err("KVM is required to use Intel vGPU\n");
+ return -ESRCH;
+ }
+
+ if (__kvmgt_vgpu_exist(vgpu, kvm))
+ return -EEXIST;
+
+ info = vzalloc(sizeof(struct kvmgt_guest_info));
+ if (!info)
+ return -ENOMEM;
+
+ vgpu->handle = (unsigned long)info;
+ info->vgpu = vgpu;
+ info->kvm = kvm;
+
+ kvmgt_protect_table_init(info);
+ gvt_cache_init(vgpu);
+
+ info->track_node.track_write = kvmgt_page_track_write;
+ info->track_node.track_flush_slot = kvmgt_page_track_flush_slot;
+ kvm_page_track_register_notifier(kvm, &info->track_node);
+
+ return 0;
+}
+
+static bool kvmgt_guest_exit(struct kvmgt_guest_info *info)
+{
+ struct intel_vgpu *vgpu;
+
+ if (!info) {
+ gvt_err("kvmgt_guest_info invalid\n");
+ return false;
+ }
+
+ vgpu = info->vgpu;
+
+ kvm_page_track_unregister_notifier(info->kvm, &info->track_node);
+ kvmgt_protect_table_destroy(info);
+ gvt_cache_destroy(vgpu);
+ vfree(info);
+
+ return true;
+}
+
static int kvmgt_attach_vgpu(void *vgpu, unsigned long *handle)
{
/* nothing to do here */
@@ -489,63 +1341,72 @@ static void kvmgt_detach_vgpu(unsigned long handle)
static int kvmgt_inject_msi(unsigned long handle, u32 addr, u16 data)
{
- struct kvmgt_guest_info *info = (struct kvmgt_guest_info *)handle;
- struct intel_vgpu *vgpu = info->vgpu;
+ struct kvmgt_guest_info *info;
+ struct intel_vgpu *vgpu;
- if (vgpu->vdev.msi_trigger)
- return eventfd_signal(vgpu->vdev.msi_trigger, 1) == 1;
+ if (!handle_valid(handle))
+ return -ESRCH;
- return false;
+ info = (struct kvmgt_guest_info *)handle;
+ vgpu = info->vgpu;
+
+ if (eventfd_signal(vgpu->vdev.msi_trigger, 1) == 1)
+ return 0;
+
+ return -EFAULT;
}
static unsigned long kvmgt_gfn_to_pfn(unsigned long handle, unsigned long gfn)
{
unsigned long pfn;
- struct kvmgt_guest_info *info = (struct kvmgt_guest_info *)handle;
+ struct kvmgt_guest_info *info;
+ struct device *dev;
int rc;
+ if (!handle_valid(handle))
+ return INTEL_GVT_INVALID_ADDR;
+
+ info = (struct kvmgt_guest_info *)handle;
pfn = gvt_cache_find(info->vgpu, gfn);
if (pfn != 0)
return pfn;
- rc = kvmgt_pin_pages(info->vgpu->vdev.mdev, &gfn, 1,
- IOMMU_READ | IOMMU_WRITE, &pfn);
+ pfn = INTEL_GVT_INVALID_ADDR;
+ dev = &info->vgpu->vdev.mdev->dev;
+ rc = vfio_pin_pages(dev, &gfn, 1, IOMMU_READ | IOMMU_WRITE, &pfn);
if (rc != 1) {
- gvt_err("vfio_pin_pages failed for gfn: 0x%lx\n", gfn);
- return 0;
+ gvt_err("vfio_pin_pages failed for gfn 0x%lx: %d\n", gfn, rc);
+ return INTEL_GVT_INVALID_ADDR;
}
gvt_cache_add(info->vgpu, gfn, pfn);
return pfn;
}
-static void *kvmgt_gpa_to_hva(unsigned long handle, unsigned long gpa)
+static int kvmgt_rw_gpa(unsigned long handle, unsigned long gpa,
+ void *buf, unsigned long len, bool write)
{
- unsigned long pfn;
- gfn_t gfn = gpa_to_gfn(gpa);
+ struct kvmgt_guest_info *info;
+ struct kvm *kvm;
+ int ret;
+ bool kthread = current->mm == NULL;
- pfn = kvmgt_gfn_to_pfn(handle, gfn);
- if (!pfn)
- return NULL;
+ if (!handle_valid(handle))
+ return -ESRCH;
- return (char *)pfn_to_kaddr(pfn) + offset_in_page(gpa);
-}
+ info = (struct kvmgt_guest_info *)handle;
+ kvm = info->kvm;
-static int kvmgt_rw_gpa(unsigned long handle, unsigned long gpa,
- void *buf, unsigned long len, bool write)
-{
- void *hva = NULL;
+ if (kthread)
+ use_mm(kvm->mm);
- hva = kvmgt_gpa_to_hva(handle, gpa);
- if (!hva)
- return -EFAULT;
+ ret = write ? kvm_write_guest(kvm, gpa, buf, len) :
+ kvm_read_guest(kvm, gpa, buf, len);
- if (write)
- memcpy(hva, buf, len);
- else
- memcpy(buf, hva, len);
+ if (kthread)
+ unuse_mm(kvm->mm);
- return 0;
+ return ret;
}
static int kvmgt_read_gpa(unsigned long handle, unsigned long gpa,
diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
index 21b6732425c5..c829cfb02fc4 100644
--- a/drivers/gpu/drm/radeon/radeon_bios.c
+++ b/drivers/gpu/drm/radeon/radeon_bios.c
@@ -603,8 +603,9 @@ static bool radeon_acpi_vfct_bios(struct radeon_device *rdev)
GOP_VBIOS_CONTENT *vbios;
VFCT_IMAGE_HEADER *vhdr;
- if (!ACPI_SUCCESS(acpi_get_table_with_size("VFCT", 1, &hdr, &tbl_size)))
+ if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
return false;
+ tbl_size = hdr->length;
if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n");
goto out_unmap;
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 08153ea4d848..6ce431323125 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -150,6 +150,29 @@ static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare)
return 0;
}
+static void dw_i2c_set_fifo_size(struct dw_i2c_dev *dev, int id)
+{
+ u32 param, tx_fifo_depth, rx_fifo_depth;
+
+ /*
+ * Try to detect the FIFO depth if not set by interface driver,
+ * the depth could be from 2 to 256 from HW spec.
+ */
+ param = i2c_dw_read_comp_param(dev);
+ tx_fifo_depth = ((param >> 16) & 0xff) + 1;
+ rx_fifo_depth = ((param >> 8) & 0xff) + 1;
+ if (!dev->tx_fifo_depth) {
+ dev->tx_fifo_depth = tx_fifo_depth;
+ dev->rx_fifo_depth = rx_fifo_depth;
+ dev->adapter.nr = id;
+ } else if (tx_fifo_depth >= 2) {
+ dev->tx_fifo_depth = min_t(u32, dev->tx_fifo_depth,
+ tx_fifo_depth);
+ dev->rx_fifo_depth = min_t(u32, dev->rx_fifo_depth,
+ rx_fifo_depth);
+ }
+}
+
static int dw_i2c_plat_probe(struct platform_device *pdev)
{
struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
@@ -245,13 +268,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
1000000);
}
- if (!dev->tx_fifo_depth) {
- u32 param1 = i2c_dw_read_comp_param(dev);
-
- dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
- dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1;
- dev->adapter.nr = pdev->id;
- }
+ dw_i2c_set_fifo_size(dev, pdev->id);
adap = &dev->adapter;
adap->owner = THIS_MODULE;
diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c
index 3d10f1a802be..1d8775799056 100644
--- a/drivers/i2c/busses/i2c-octeon-core.c
+++ b/drivers/i2c/busses/i2c-octeon-core.c
@@ -342,7 +342,9 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
if (result)
return result;
- data[i] = octeon_i2c_data_read(i2c);
+ data[i] = octeon_i2c_data_read(i2c, &result);
+ if (result)
+ return result;
if (recv_len && i == 0) {
if (data[i] > I2C_SMBUS_BLOCK_MAX + 1)
return -EPROTO;
diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h
index 87151ea74acd..e160f838c254 100644
--- a/drivers/i2c/busses/i2c-octeon-core.h
+++ b/drivers/i2c/busses/i2c-octeon-core.h
@@ -141,11 +141,14 @@ static inline void octeon_i2c_writeq_flush(u64 val, void __iomem *addr)
*/
static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
{
+ int tries = 1000;
u64 tmp;
__raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI(i2c));
do {
tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+ if (--tries < 0)
+ return;
} while ((tmp & SW_TWSI_V) != 0);
}
@@ -163,24 +166,32 @@ static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8
*
* The I2C core registers are accessed indirectly via the SW_TWSI CSR.
*/
-static inline u8 octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg)
+static inline int octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg,
+ int *error)
{
+ int tries = 1000;
u64 tmp;
__raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI(i2c));
do {
tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+ if (--tries < 0) {
+ /* signal that the returned data is invalid */
+ if (error)
+ *error = -EIO;
+ return 0;
+ }
} while ((tmp & SW_TWSI_V) != 0);
return tmp & 0xFF;
}
#define octeon_i2c_ctl_read(i2c) \
- octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL)
-#define octeon_i2c_data_read(i2c) \
- octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA)
+ octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL, NULL)
+#define octeon_i2c_data_read(i2c, error) \
+ octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA, error)
#define octeon_i2c_stat_read(i2c) \
- octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT)
+ octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT, NULL)
/**
* octeon_i2c_read_int - read the TWSI_INT register
diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c
index 05cf192ef1ac..0ab1e55558bc 100644
--- a/drivers/i2c/busses/i2c-xgene-slimpro.c
+++ b/drivers/i2c/busses/i2c-xgene-slimpro.c
@@ -415,6 +415,7 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev)
adapter->algo = &xgene_slimpro_i2c_algorithm;
adapter->class = I2C_CLASS_HWMON;
adapter->dev.parent = &pdev->dev;
+ adapter->dev.of_node = pdev->dev.of_node;
i2c_set_adapdata(adapter, ctx);
rc = i2c_add_adapter(adapter);
if (rc) {
diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c
index 3ab654bbfab5..b7ca249ec9c3 100644
--- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c
+++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c
@@ -95,6 +95,7 @@ static int mlxcpld_mux_reg_write(struct i2c_adapter *adap,
struct i2c_client *client, u8 val)
{
struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev);
+ int ret = -ENODEV;
if (adap->algo->master_xfer) {
struct i2c_msg msg;
@@ -104,17 +105,21 @@ static int mlxcpld_mux_reg_write(struct i2c_adapter *adap,
msg.flags = 0;
msg.len = 2;
msg.buf = msgbuf;
- return __i2c_transfer(adap, &msg, 1);
+ ret = __i2c_transfer(adap, &msg, 1);
+
+ if (ret >= 0 && ret != 1)
+ ret = -EREMOTEIO;
} else if (adap->algo->smbus_xfer) {
union i2c_smbus_data data;
data.byte = val;
- return adap->algo->smbus_xfer(adap, client->addr,
- client->flags, I2C_SMBUS_WRITE,
- pdata->sel_reg_addr,
- I2C_SMBUS_BYTE_DATA, &data);
- } else
- return -ENODEV;
+ ret = adap->algo->smbus_xfer(adap, client->addr,
+ client->flags, I2C_SMBUS_WRITE,
+ pdata->sel_reg_addr,
+ I2C_SMBUS_BYTE_DATA, &data);
+ }
+
+ return ret;
}
static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
@@ -127,10 +132,7 @@ static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
/* Only select the channel if its different from the last channel */
if (data->last_chan != regval) {
err = mlxcpld_mux_reg_write(muxc->parent, client, regval);
- if (err)
- data->last_chan = 0;
- else
- data->last_chan = regval;
+ data->last_chan = err < 0 ? 0 : regval;
}
return err;
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 9a348ee4dc14..dd18b9ccb1f4 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -167,6 +167,9 @@ static int pca954x_reg_write(struct i2c_adapter *adap,
buf[0] = val;
msg.buf = buf;
ret = __i2c_transfer(adap, &msg, 1);
+
+ if (ret >= 0 && ret != 1)
+ ret = -EREMOTEIO;
} else {
union i2c_smbus_data data;
ret = adap->algo->smbus_xfer(adap, client->addr,
@@ -195,7 +198,7 @@ static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
/* Only select the channel if its different from the last channel */
if (data->last_chan != regval) {
ret = pca954x_reg_write(muxc->parent, client, regval);
- data->last_chan = ret ? 0 : regval;
+ data->last_chan = ret < 0 ? 0 : regval;
}
return ret;
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 83af17ad0f1f..6d9499658671 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -134,6 +134,7 @@ static const struct xpad_device {
{ 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
{ 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE },
{ 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", 0, XTYPE_XBOXONE },
+ { 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE },
{ 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
@@ -1044,9 +1045,9 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
packet->data[7] = 0x00;
packet->data[8] = strong / 512; /* left actuator */
packet->data[9] = weak / 512; /* right actuator */
- packet->data[10] = 0xFF;
- packet->data[11] = 0x00;
- packet->data[12] = 0x00;
+ packet->data[10] = 0xFF; /* on period */
+ packet->data[11] = 0x00; /* off period */
+ packet->data[12] = 0xFF; /* repeat count */
packet->len = 13;
packet->pending = true;
break;
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 29093657f2ef..582462d0af75 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -26,15 +26,15 @@
#include <linux/gpio_keys.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/spinlock.h>
struct gpio_button_data {
const struct gpio_keys_button *button;
struct input_dev *input;
+ struct gpio_desc *gpiod;
struct timer_list release_timer;
unsigned int release_delay; /* in msecs, for IRQ-only buttons */
@@ -140,7 +140,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)
*/
disable_irq(bdata->irq);
- if (gpio_is_valid(bdata->button->gpio))
+ if (bdata->gpiod)
cancel_delayed_work_sync(&bdata->work);
else
del_timer_sync(&bdata->release_timer);
@@ -358,19 +358,20 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
const struct gpio_keys_button *button = bdata->button;
struct input_dev *input = bdata->input;
unsigned int type = button->type ?: EV_KEY;
- int state = gpio_get_value_cansleep(button->gpio);
+ int state;
+ state = gpiod_get_value_cansleep(bdata->gpiod);
if (state < 0) {
- dev_err(input->dev.parent, "failed to get gpio state\n");
+ dev_err(input->dev.parent,
+ "failed to get gpio state: %d\n", state);
return;
}
- state = (state ? 1 : 0) ^ button->active_low;
if (type == EV_ABS) {
if (state)
input_event(input, type, button->code, button->value);
} else {
- input_event(input, type, button->code, !!state);
+ input_event(input, type, button->code, state);
}
input_sync(input);
}
@@ -456,7 +457,7 @@ static void gpio_keys_quiesce_key(void *data)
{
struct gpio_button_data *bdata = data;
- if (gpio_is_valid(bdata->button->gpio))
+ if (bdata->gpiod)
cancel_delayed_work_sync(&bdata->work);
else
del_timer_sync(&bdata->release_timer);
@@ -465,7 +466,8 @@ static void gpio_keys_quiesce_key(void *data)
static int gpio_keys_setup_key(struct platform_device *pdev,
struct input_dev *input,
struct gpio_button_data *bdata,
- const struct gpio_keys_button *button)
+ const struct gpio_keys_button *button,
+ struct fwnode_handle *child)
{
const char *desc = button->desc ? button->desc : "gpio_keys";
struct device *dev = &pdev->dev;
@@ -478,18 +480,56 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
bdata->button = button;
spin_lock_init(&bdata->lock);
- if (gpio_is_valid(button->gpio)) {
+ if (child) {
+ bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, child);
+ if (IS_ERR(bdata->gpiod)) {
+ error = PTR_ERR(bdata->gpiod);
+ if (error == -ENOENT) {
+ /*
+ * GPIO is optional, we may be dealing with
+ * purely interrupt-driven setup.
+ */
+ bdata->gpiod = NULL;
+ } else {
+ if (error != -EPROBE_DEFER)
+ dev_err(dev, "failed to get gpio: %d\n",
+ error);
+ return error;
+ }
+ } else {
+ error = gpiod_direction_input(bdata->gpiod);
+ if (error) {
+ dev_err(dev, "Failed to configure GPIO %d as input: %d\n",
+ desc_to_gpio(bdata->gpiod), error);
+ return error;
+ }
+ }
+ } else if (gpio_is_valid(button->gpio)) {
+ /*
+ * Legacy GPIO number, so request the GPIO here and
+ * convert it to descriptor.
+ */
+ unsigned flags = GPIOF_IN;
+
+ if (button->active_low)
+ flags |= GPIOF_ACTIVE_LOW;
- error = devm_gpio_request_one(&pdev->dev, button->gpio,
- GPIOF_IN, desc);
+ error = devm_gpio_request_one(&pdev->dev, button->gpio, flags,
+ desc);
if (error < 0) {
dev_err(dev, "Failed to request GPIO %d, error %d\n",
button->gpio, error);
return error;
}
+ bdata->gpiod = gpio_to_desc(button->gpio);
+ if (!bdata->gpiod)
+ return -EINVAL;
+ }
+
+ if (bdata->gpiod) {
if (button->debounce_interval) {
- error = gpio_set_debounce(button->gpio,
+ error = gpiod_set_debounce(bdata->gpiod,
button->debounce_interval * 1000);
/* use timer if gpiolib doesn't provide debounce */
if (error < 0)
@@ -500,7 +540,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
if (button->irq) {
bdata->irq = button->irq;
} else {
- irq = gpio_to_irq(button->gpio);
+ irq = gpiod_to_irq(bdata->gpiod);
if (irq < 0) {
error = irq;
dev_err(dev,
@@ -518,9 +558,10 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
} else {
if (!button->irq) {
- dev_err(dev, "No IRQ specified\n");
+ dev_err(dev, "Found button without gpio or irq\n");
return -EINVAL;
}
+
bdata->irq = button->irq;
if (button->type && button->type != EV_KEY) {
@@ -575,7 +616,7 @@ static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i];
- if (gpio_is_valid(bdata->button->gpio))
+ if (bdata->gpiod)
gpio_keys_gpio_report_event(bdata);
}
input_sync(input);
@@ -612,25 +653,18 @@ static void gpio_keys_close(struct input_dev *input)
* Handlers for alternative sources of platform_data
*/
-#ifdef CONFIG_OF
/*
- * Translate OpenFirmware node properties into platform_data
+ * Translate properties into platform_data
*/
static struct gpio_keys_platform_data *
gpio_keys_get_devtree_pdata(struct device *dev)
{
- struct device_node *node, *pp;
struct gpio_keys_platform_data *pdata;
struct gpio_keys_button *button;
- int error;
+ struct fwnode_handle *child;
int nbuttons;
- int i;
- node = dev->of_node;
- if (!node)
- return ERR_PTR(-ENODEV);
-
- nbuttons = of_get_available_child_count(node);
+ nbuttons = device_get_child_node_count(dev);
if (nbuttons == 0)
return ERR_PTR(-ENODEV);
@@ -640,64 +674,47 @@ gpio_keys_get_devtree_pdata(struct device *dev)
if (!pdata)
return ERR_PTR(-ENOMEM);
- pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
- pdata->nbuttons = nbuttons;
-
- pdata->rep = !!of_get_property(node, "autorepeat", NULL);
-
- of_property_read_string(node, "label", &pdata->name);
-
- i = 0;
- for_each_available_child_of_node(node, pp) {
- enum of_gpio_flags flags;
+ button = (struct gpio_keys_button *)(pdata + 1);
- button = &pdata->buttons[i++];
+ pdata->buttons = button;
+ pdata->nbuttons = nbuttons;
- button->gpio = of_get_gpio_flags(pp, 0, &flags);
- if (button->gpio < 0) {
- error = button->gpio;
- if (error != -ENOENT) {
- if (error != -EPROBE_DEFER)
- dev_err(dev,
- "Failed to get gpio flags, error: %d\n",
- error);
- return ERR_PTR(error);
- }
- } else {
- button->active_low = flags & OF_GPIO_ACTIVE_LOW;
- }
+ pdata->rep = device_property_read_bool(dev, "autorepeat");
- button->irq = irq_of_parse_and_map(pp, 0);
+ device_property_read_string(dev, "label", &pdata->name);
- if (!gpio_is_valid(button->gpio) && !button->irq) {
- dev_err(dev, "Found button without gpios or irqs\n");
- return ERR_PTR(-EINVAL);
- }
+ device_for_each_child_node(dev, child) {
+ if (is_of_node(child))
+ button->irq =
+ irq_of_parse_and_map(to_of_node(child), 0);
- if (of_property_read_u32(pp, "linux,code", &button->code)) {
- dev_err(dev, "Button without keycode: 0x%x\n",
- button->gpio);
+ if (fwnode_property_read_u32(child, "linux,code",
+ &button->code)) {
+ dev_err(dev, "Button without keycode\n");
+ fwnode_handle_put(child);
return ERR_PTR(-EINVAL);
}
- button->desc = of_get_property(pp, "label", NULL);
+ fwnode_property_read_string(child, "label", &button->desc);
- if (of_property_read_u32(pp, "linux,input-type", &button->type))
+ if (fwnode_property_read_u32(child, "linux,input-type",
+ &button->type))
button->type = EV_KEY;
- button->wakeup = of_property_read_bool(pp, "wakeup-source") ||
- /* legacy name */
- of_property_read_bool(pp, "gpio-key,wakeup");
+ button->wakeup =
+ fwnode_property_read_bool(child, "wakeup-source") ||
+ /* legacy name */
+ fwnode_property_read_bool(child, "gpio-key,wakeup");
- button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL);
+ button->can_disable =
+ fwnode_property_read_bool(child, "linux,can-disable");
- if (of_property_read_u32(pp, "debounce-interval",
+ if (fwnode_property_read_u32(child, "debounce-interval",
&button->debounce_interval))
button->debounce_interval = 5;
- }
- if (pdata->nbuttons == 0)
- return ERR_PTR(-EINVAL);
+ button++;
+ }
return pdata;
}
@@ -708,20 +725,11 @@ static const struct of_device_id gpio_keys_of_match[] = {
};
MODULE_DEVICE_TABLE(of, gpio_keys_of_match);
-#else
-
-static inline struct gpio_keys_platform_data *
-gpio_keys_get_devtree_pdata(struct device *dev)
-{
- return ERR_PTR(-ENODEV);
-}
-
-#endif
-
static int gpio_keys_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
+ struct fwnode_handle *child = NULL;
struct gpio_keys_drvdata *ddata;
struct input_dev *input;
size_t size;
@@ -774,14 +782,28 @@ static int gpio_keys_probe(struct platform_device *pdev)
const struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_button_data *bdata = &ddata->data[i];
- error = gpio_keys_setup_key(pdev, input, bdata, button);
- if (error)
+ if (!dev_get_platdata(dev)) {
+ child = device_get_next_child_node(&pdev->dev, child);
+ if (!child) {
+ dev_err(&pdev->dev,
+ "missing child device node for entry %d\n",
+ i);
+ return -EINVAL;
+ }
+ }
+
+ error = gpio_keys_setup_key(pdev, input, bdata, button, child);
+ if (error) {
+ fwnode_handle_put(child);
return error;
+ }
if (button->wakeup)
wakeup = 1;
}
+ fwnode_handle_put(child);
+
error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
if (error) {
dev_err(dev, "Unable to export keys/switches, error: %d\n",
@@ -814,8 +836,7 @@ static int gpio_keys_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int gpio_keys_suspend(struct device *dev)
+static int __maybe_unused gpio_keys_suspend(struct device *dev)
{
struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
struct input_dev *input = ddata->input;
@@ -837,7 +858,7 @@ static int gpio_keys_suspend(struct device *dev)
return 0;
}
-static int gpio_keys_resume(struct device *dev)
+static int __maybe_unused gpio_keys_resume(struct device *dev)
{
struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
struct input_dev *input = ddata->input;
@@ -863,7 +884,6 @@ static int gpio_keys_resume(struct device *dev)
gpio_keys_report_state(ddata);
return 0;
}
-#endif
static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
@@ -873,7 +893,7 @@ static struct platform_driver gpio_keys_device_driver = {
.driver = {
.name = "gpio-keys",
.pm = &gpio_keys_pm_ops,
- .of_match_table = of_match_ptr(gpio_keys_of_match),
+ .of_match_table = gpio_keys_of_match,
}
};
diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
index 62bdb1d48c49..bed4f2086158 100644
--- a/drivers/input/keyboard/gpio_keys_polled.c
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -30,10 +30,10 @@
#define DRV_NAME "gpio-keys-polled"
struct gpio_keys_button_data {
+ struct gpio_desc *gpiod;
int last_state;
int count;
int threshold;
- int can_sleep;
};
struct gpio_keys_polled_dev {
@@ -46,7 +46,7 @@ struct gpio_keys_polled_dev {
};
static void gpio_keys_button_event(struct input_polled_dev *dev,
- struct gpio_keys_button *button,
+ const struct gpio_keys_button *button,
int state)
{
struct gpio_keys_polled_dev *bdev = dev->private;
@@ -70,21 +70,22 @@ static void gpio_keys_button_event(struct input_polled_dev *dev,
}
static void gpio_keys_polled_check_state(struct input_polled_dev *dev,
- struct gpio_keys_button *button,
+ const struct gpio_keys_button *button,
struct gpio_keys_button_data *bdata)
{
int state;
- if (bdata->can_sleep)
- state = !!gpiod_get_value_cansleep(button->gpiod);
- else
- state = !!gpiod_get_value(button->gpiod);
-
- gpio_keys_button_event(dev, button, state);
+ state = gpiod_get_value_cansleep(bdata->gpiod);
+ if (state < 0) {
+ dev_err(dev->input->dev.parent,
+ "failed to get gpio state: %d\n", state);
+ } else {
+ gpio_keys_button_event(dev, button, state);
- if (state != bdata->last_state) {
- bdata->count = 0;
- bdata->last_state = state;
+ if (state != bdata->last_state) {
+ bdata->count = 0;
+ bdata->last_state = state;
+ }
}
}
@@ -142,48 +143,35 @@ static void gpio_keys_polled_close(struct input_polled_dev *dev)
pdata->disable(bdev->dev);
}
-static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev)
+static struct gpio_keys_platform_data *
+gpio_keys_polled_get_devtree_pdata(struct device *dev)
{
struct gpio_keys_platform_data *pdata;
struct gpio_keys_button *button;
struct fwnode_handle *child;
- int error;
int nbuttons;
nbuttons = device_get_child_node_count(dev);
if (nbuttons == 0)
- return NULL;
+ return ERR_PTR(-EINVAL);
pdata = devm_kzalloc(dev, sizeof(*pdata) + nbuttons * sizeof(*button),
GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
- pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
+ button = (struct gpio_keys_button *)(pdata + 1);
+
+ pdata->buttons = button;
+ pdata->nbuttons = nbuttons;
pdata->rep = device_property_present(dev, "autorepeat");
device_property_read_u32(dev, "poll-interval", &pdata->poll_interval);
device_for_each_child_node(dev, child) {
- struct gpio_desc *desc;
-
- desc = devm_get_gpiod_from_child(dev, NULL, child);
- if (IS_ERR(desc)) {
- error = PTR_ERR(desc);
- if (error != -EPROBE_DEFER)
- dev_err(dev,
- "Failed to get gpio flags, error: %d\n",
- error);
- fwnode_handle_put(child);
- return ERR_PTR(error);
- }
-
- button = &pdata->buttons[pdata->nbuttons++];
- button->gpiod = desc;
-
- if (fwnode_property_read_u32(child, "linux,code", &button->code)) {
- dev_err(dev, "Button without keycode: %d\n",
- pdata->nbuttons - 1);
+ if (fwnode_property_read_u32(child, "linux,code",
+ &button->code)) {
+ dev_err(dev, "button without keycode\n");
fwnode_handle_put(child);
return ERR_PTR(-EINVAL);
}
@@ -206,10 +194,9 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
if (fwnode_property_read_u32(child, "debounce-interval",
&button->debounce_interval))
button->debounce_interval = 5;
- }
- if (pdata->nbuttons == 0)
- return ERR_PTR(-EINVAL);
+ button++;
+ }
return pdata;
}
@@ -220,7 +207,7 @@ static void gpio_keys_polled_set_abs_params(struct input_dev *input,
int i, min = 0, max = 0;
for (i = 0; i < pdata->nbuttons; i++) {
- struct gpio_keys_button *button = &pdata->buttons[i];
+ const struct gpio_keys_button *button = &pdata->buttons[i];
if (button->type != EV_ABS || button->code != code)
continue;
@@ -230,6 +217,7 @@ static void gpio_keys_polled_set_abs_params(struct input_dev *input,
if (button->value > max)
max = button->value;
}
+
input_set_abs_params(input, code, min, max, 0, 0);
}
@@ -242,6 +230,7 @@ MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);
static int gpio_keys_polled_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct fwnode_handle *child = NULL;
const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
struct gpio_keys_polled_dev *bdev;
struct input_polled_dev *poll_dev;
@@ -254,10 +243,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
pdata = gpio_keys_polled_get_devtree_pdata(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
- if (!pdata) {
- dev_err(dev, "missing platform data\n");
- return -EINVAL;
- }
}
if (!pdata->poll_interval) {
@@ -300,20 +285,48 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
__set_bit(EV_REP, input->evbit);
for (i = 0; i < pdata->nbuttons; i++) {
- struct gpio_keys_button *button = &pdata->buttons[i];
+ const struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_keys_button_data *bdata = &bdev->data[i];
unsigned int type = button->type ?: EV_KEY;
if (button->wakeup) {
dev_err(dev, DRV_NAME " does not support wakeup\n");
+ fwnode_handle_put(child);
return -EINVAL;
}
- /*
- * Legacy GPIO number so request the GPIO here and
- * convert it to descriptor.
- */
- if (!button->gpiod && gpio_is_valid(button->gpio)) {
+ if (!dev_get_platdata(dev)) {
+ /* No legacy static platform data */
+ child = device_get_next_child_node(dev, child);
+ if (!child) {
+ dev_err(dev, "missing child device node\n");
+ return -EINVAL;
+ }
+
+ bdata->gpiod = devm_get_gpiod_from_child(dev, NULL,
+ child);
+ if (IS_ERR(bdata->gpiod)) {
+ error = PTR_ERR(bdata->gpiod);
+ if (error != -EPROBE_DEFER)
+ dev_err(dev,
+ "failed to get gpio: %d\n",
+ error);
+ fwnode_handle_put(child);
+ return error;
+ }
+
+ error = gpiod_direction_input(bdata->gpiod);
+ if (error) {
+ dev_err(dev, "Failed to configure GPIO %d as input: %d\n",
+ desc_to_gpio(bdata->gpiod), error);
+ fwnode_handle_put(child);
+ return error;
+ }
+ } else if (gpio_is_valid(button->gpio)) {
+ /*
+ * Legacy GPIO number so request the GPIO here and
+ * convert it to descriptor.
+ */
unsigned flags = GPIOF_IN;
if (button->active_low)
@@ -322,18 +335,21 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
error = devm_gpio_request_one(&pdev->dev, button->gpio,
flags, button->desc ? : DRV_NAME);
if (error) {
- dev_err(dev, "unable to claim gpio %u, err=%d\n",
+ dev_err(dev,
+ "unable to claim gpio %u, err=%d\n",
button->gpio, error);
return error;
}
- button->gpiod = gpio_to_desc(button->gpio);
+ bdata->gpiod = gpio_to_desc(button->gpio);
+ if (!bdata->gpiod) {
+ dev_err(dev,
+ "unable to convert gpio %u to descriptor\n",
+ button->gpio);
+ return -EINVAL;
+ }
}
- if (IS_ERR(button->gpiod))
- return PTR_ERR(button->gpiod);
-
- bdata->can_sleep = gpiod_cansleep(button->gpiod);
bdata->last_state = -1;
bdata->threshold = DIV_ROUND_UP(button->debounce_interval,
pdata->poll_interval);
@@ -344,6 +360,8 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
button->code);
}
+ fwnode_handle_put(child);
+
bdev->poll_dev = poll_dev;
bdev->dev = dev;
bdev->pdata = pdata;
diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c
index 265d641c40e2..632523d4f5dc 100644
--- a/drivers/input/keyboard/lpc32xx-keys.c
+++ b/drivers/input/keyboard/lpc32xx-keys.c
@@ -182,7 +182,7 @@ static int lpc32xx_kscan_probe(struct platform_device *pdev)
}
irq = platform_get_irq(pdev, 0);
- if (irq < 0 || irq >= NR_IRQS) {
+ if (irq < 0) {
dev_err(&pdev->dev, "failed to get platform irq\n");
return -EINVAL;
}
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c
index fcef5d1365e2..e24443376e75 100644
--- a/drivers/input/keyboard/pxa27x_keypad.c
+++ b/drivers/input/keyboard/pxa27x_keypad.c
@@ -316,7 +316,7 @@ static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
error = of_property_read_u32(np, "marvell,debounce-interval",
&pdata->debounce_interval);
if (error) {
- dev_err(dev, "failed to parse debpunce-interval\n");
+ dev_err(dev, "failed to parse debounce-interval\n");
return error;
}
diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c
index 9002298698fc..3048ef3e3e16 100644
--- a/drivers/input/keyboard/tca8418_keypad.c
+++ b/drivers/input/keyboard/tca8418_keypad.c
@@ -164,11 +164,18 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data)
int error, col, row;
u8 reg, state, code;
- /* Initial read of the key event FIFO */
- error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
+ do {
+ error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
+ if (error < 0) {
+ dev_err(&keypad_data->client->dev,
+ "unable to read REG_KEY_EVENT_A\n");
+ break;
+ }
+
+ /* Assume that key code 0 signifies empty FIFO */
+ if (reg <= 0)
+ break;
- /* Assume that key code 0 signifies empty FIFO */
- while (error >= 0 && reg > 0) {
state = reg & KEY_EVENT_VALUE;
code = reg & KEY_EVENT_CODE;
@@ -184,11 +191,7 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data)
/* Read for next loop */
error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
- }
-
- if (error < 0)
- dev_err(&keypad_data->client->dev,
- "unable to read REG_KEY_EVENT_A\n");
+ } while (1);
input_sync(input);
}
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 7ffb614ce566..1ae4d9617ff8 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -625,11 +625,12 @@ config INPUT_DA9055_ONKEY
will be called da9055_onkey.
config INPUT_DA9063_ONKEY
- tristate "Dialog DA9062/63 OnKey"
+ tristate "Dialog DA9063/62/61 OnKey"
depends on MFD_DA9063 || MFD_DA9062
help
- Support the ONKEY of Dialog DA9063 and DA9062 Power Management ICs
- as an input device capable of reporting the power button status.
+ Support the ONKEY of Dialog DA9063, DA9062 and DA9061 Power
+ Management ICs as an input device capable of reporting the
+ power button status.
To compile this driver as a module, choose M here: the module
will be called da9063_onkey.
diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c
index b0d445390ee4..2124390ec38c 100644
--- a/drivers/input/misc/bma150.c
+++ b/drivers/input/misc/bma150.c
@@ -538,8 +538,13 @@ static int bma150_probe(struct i2c_client *client,
return -EIO;
}
+ /*
+ * Note if the IIO CONFIG_BMA180 driver is enabled we want to fail
+ * the probe for the bma180 as the iio driver is preferred.
+ */
chip_id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG);
- if (chip_id != BMA150_CHIP_ID && chip_id != BMA180_CHIP_ID) {
+ if (chip_id != BMA150_CHIP_ID &&
+ (IS_ENABLED(CONFIG_BMA180) || chip_id != BMA180_CHIP_ID)) {
dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id);
return -EINVAL;
}
@@ -643,7 +648,9 @@ static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL);
static const struct i2c_device_id bma150_id[] = {
{ "bma150", 0 },
+#if !IS_ENABLED(CONFIG_BMA180)
{ "bma180", 0 },
+#endif
{ "smb380", 0 },
{ "bma023", 0 },
{ }
diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c
index bb863e062b03..b4ff1e86d3d3 100644
--- a/drivers/input/misc/da9063_onkey.c
+++ b/drivers/input/misc/da9063_onkey.c
@@ -1,5 +1,5 @@
/*
- * OnKey device driver for DA9063 and DA9062 PMICs
+ * OnKey device driver for DA9063, DA9062 and DA9061 PMICs
* Copyright (C) 2015 Dialog Semiconductor Ltd.
*
* This program is free software; you can redistribute it and/or
@@ -87,6 +87,7 @@ static const struct of_device_id da9063_compatible_reg_id_table[] = {
{ .compatible = "dlg,da9062-onkey", .data = &da9062_regs },
{ },
};
+MODULE_DEVICE_TABLE(of, da9063_compatible_reg_id_table);
static void da9063_poll_on(struct work_struct *work)
{
@@ -149,13 +150,13 @@ static void da9063_poll_on(struct work_struct *work)
* and then send shutdown command
*/
dev_dbg(&onkey->input->dev,
- "Sending SHUTDOWN to DA9063 ...\n");
+ "Sending SHUTDOWN to PMIC ...\n");
error = regmap_write(onkey->regmap,
config->onkey_shutdown,
config->onkey_shutdown_mask);
if (error)
dev_err(&onkey->input->dev,
- "Cannot SHUTDOWN DA9063: %d\n",
+ "Cannot SHUTDOWN PMIC: %d\n",
error);
}
}
@@ -300,6 +301,6 @@ static struct platform_driver da9063_onkey_driver = {
module_platform_driver(da9063_onkey_driver);
MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
-MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063 and DA9062");
+MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063, DA9062 and DA9061");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY);
diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c
index 2adfd86c869a..0a2b865b1000 100644
--- a/drivers/input/misc/drv260x.c
+++ b/drivers/input/misc/drv260x.c
@@ -18,8 +18,6 @@
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -27,7 +25,6 @@
#include <linux/regulator/consumer.h>
#include <dt-bindings/input/ti-drv260x.h>
-#include <linux/platform_data/drv260x-pdata.h>
#define DRV260X_STATUS 0x0
#define DRV260X_MODE 0x1
@@ -468,90 +465,39 @@ static const struct regmap_config drv260x_regmap_config = {
.cache_type = REGCACHE_NONE,
};
-#ifdef CONFIG_OF
-static int drv260x_parse_dt(struct device *dev,
- struct drv260x_data *haptics)
-{
- struct device_node *np = dev->of_node;
- unsigned int voltage;
- int error;
-
- error = of_property_read_u32(np, "mode", &haptics->mode);
- if (error) {
- dev_err(dev, "%s: No entry for mode\n", __func__);
- return error;
- }
-
- error = of_property_read_u32(np, "library-sel", &haptics->library);
- if (error) {
- dev_err(dev, "%s: No entry for library selection\n",
- __func__);
- return error;
- }
-
- error = of_property_read_u32(np, "vib-rated-mv", &voltage);
- if (!error)
- haptics->rated_voltage = drv260x_calculate_voltage(voltage);
-
-
- error = of_property_read_u32(np, "vib-overdrive-mv", &voltage);
- if (!error)
- haptics->overdrive_voltage = drv260x_calculate_voltage(voltage);
-
- return 0;
-}
-#else
-static inline int drv260x_parse_dt(struct device *dev,
- struct drv260x_data *haptics)
-{
- dev_err(dev, "no platform data defined\n");
-
- return -EINVAL;
-}
-#endif
-
static int drv260x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- const struct drv260x_platform_data *pdata = dev_get_platdata(&client->dev);
+ struct device *dev = &client->dev;
struct drv260x_data *haptics;
+ u32 voltage;
int error;
- haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL);
+ haptics = devm_kzalloc(dev, sizeof(*haptics), GFP_KERNEL);
if (!haptics)
return -ENOMEM;
- haptics->rated_voltage = DRV260X_DEF_OD_CLAMP_VOLT;
- haptics->rated_voltage = DRV260X_DEF_RATED_VOLT;
-
- if (pdata) {
- haptics->mode = pdata->mode;
- haptics->library = pdata->library_selection;
- if (pdata->vib_overdrive_voltage)
- haptics->overdrive_voltage = drv260x_calculate_voltage(pdata->vib_overdrive_voltage);
- if (pdata->vib_rated_voltage)
- haptics->rated_voltage = drv260x_calculate_voltage(pdata->vib_rated_voltage);
- } else if (client->dev.of_node) {
- error = drv260x_parse_dt(&client->dev, haptics);
- if (error)
- return error;
- } else {
- dev_err(&client->dev, "Platform data not set\n");
- return -ENODEV;
+ error = device_property_read_u32(dev, "mode", &haptics->mode);
+ if (error) {
+ dev_err(dev, "Can't fetch 'mode' property: %d\n", error);
+ return error;
}
-
if (haptics->mode < DRV260X_LRA_MODE ||
haptics->mode > DRV260X_ERM_MODE) {
- dev_err(&client->dev,
- "Vibrator mode is invalid: %i\n",
- haptics->mode);
+ dev_err(dev, "Vibrator mode is invalid: %i\n", haptics->mode);
return -EINVAL;
}
+ error = device_property_read_u32(dev, "library-sel", &haptics->library);
+ if (error) {
+ dev_err(dev, "Can't fetch 'library-sel' property: %d\n", error);
+ return error;
+ }
+
if (haptics->library < DRV260X_LIB_EMPTY ||
haptics->library > DRV260X_ERM_LIB_F) {
- dev_err(&client->dev,
+ dev_err(dev,
"Library value is invalid: %i\n", haptics->library);
return -EINVAL;
}
@@ -559,40 +505,44 @@ static int drv260x_probe(struct i2c_client *client,
if (haptics->mode == DRV260X_LRA_MODE &&
haptics->library != DRV260X_LIB_EMPTY &&
haptics->library != DRV260X_LIB_LRA) {
- dev_err(&client->dev,
- "LRA Mode with ERM Library mismatch\n");
+ dev_err(dev, "LRA Mode with ERM Library mismatch\n");
return -EINVAL;
}
if (haptics->mode == DRV260X_ERM_MODE &&
(haptics->library == DRV260X_LIB_EMPTY ||
haptics->library == DRV260X_LIB_LRA)) {
- dev_err(&client->dev,
- "ERM Mode with LRA Library mismatch\n");
+ dev_err(dev, "ERM Mode with LRA Library mismatch\n");
return -EINVAL;
}
- haptics->regulator = devm_regulator_get(&client->dev, "vbat");
+ error = device_property_read_u32(dev, "vib-rated-mv", &voltage);
+ haptics->rated_voltage = error ? DRV260X_DEF_RATED_VOLT :
+ drv260x_calculate_voltage(voltage);
+
+ error = device_property_read_u32(dev, "vib-overdrive-mv", &voltage);
+ haptics->overdrive_voltage = error ? DRV260X_DEF_OD_CLAMP_VOLT :
+ drv260x_calculate_voltage(voltage);
+
+ haptics->regulator = devm_regulator_get(dev, "vbat");
if (IS_ERR(haptics->regulator)) {
error = PTR_ERR(haptics->regulator);
- dev_err(&client->dev,
- "unable to get regulator, error: %d\n", error);
+ dev_err(dev, "unable to get regulator, error: %d\n", error);
return error;
}
- haptics->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable",
+ haptics->enable_gpio = devm_gpiod_get_optional(dev, "enable",
GPIOD_OUT_HIGH);
if (IS_ERR(haptics->enable_gpio))
return PTR_ERR(haptics->enable_gpio);
- haptics->input_dev = devm_input_allocate_device(&client->dev);
+ haptics->input_dev = devm_input_allocate_device(dev);
if (!haptics->input_dev) {
dev_err(&client->dev, "Failed to allocate input device\n");
return -ENOMEM;
}
haptics->input_dev->name = "drv260x:haptics";
- haptics->input_dev->dev.parent = client->dev.parent;
haptics->input_dev->close = drv260x_close;
input_set_drvdata(haptics->input_dev, haptics);
input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE);
@@ -600,8 +550,7 @@ static int drv260x_probe(struct i2c_client *client,
error = input_ff_create_memless(haptics->input_dev, NULL,
drv260x_haptics_play);
if (error) {
- dev_err(&client->dev, "input_ff_create() failed: %d\n",
- error);
+ dev_err(dev, "input_ff_create() failed: %d\n", error);
return error;
}
@@ -613,21 +562,19 @@ static int drv260x_probe(struct i2c_client *client,
haptics->regmap = devm_regmap_init_i2c(client, &drv260x_regmap_config);
if (IS_ERR(haptics->regmap)) {
error = PTR_ERR(haptics->regmap);
- dev_err(&client->dev, "Failed to allocate register map: %d\n",
- error);
+ dev_err(dev, "Failed to allocate register map: %d\n", error);
return error;
}
error = drv260x_init(haptics);
if (error) {
- dev_err(&client->dev, "Device init failed: %d\n", error);
+ dev_err(dev, "Device init failed: %d\n", error);
return error;
}
error = input_register_device(haptics->input_dev);
if (error) {
- dev_err(&client->dev, "couldn't register input device: %d\n",
- error);
+ dev_err(dev, "couldn't register input device: %d\n", error);
return error;
}
diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c
index ef9bc12b3be3..dcb6d8e94b11 100644
--- a/drivers/input/misc/drv2665.c
+++ b/drivers/input/misc/drv2665.c
@@ -125,8 +125,8 @@ static void drv2665_close(struct input_dev *input)
cancel_work_sync(&haptics->work);
- error = regmap_update_bits(haptics->regmap,
- DRV2665_CTRL_2, DRV2665_STANDBY, 1);
+ error = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
+ DRV2665_STANDBY, DRV2665_STANDBY);
if (error)
dev_err(&haptics->client->dev,
"Failed to enter standby mode: %d\n", error);
@@ -240,7 +240,7 @@ static int __maybe_unused drv2665_suspend(struct device *dev)
if (haptics->input_dev->users) {
ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
- DRV2665_STANDBY, 1);
+ DRV2665_STANDBY, DRV2665_STANDBY);
if (ret) {
dev_err(dev, "Failed to set standby mode\n");
regulator_disable(haptics->regulator);
diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c
index d5ba7481328c..2849bb6906a8 100644
--- a/drivers/input/misc/drv2667.c
+++ b/drivers/input/misc/drv2667.c
@@ -256,7 +256,7 @@ static void drv2667_close(struct input_dev *input)
cancel_work_sync(&haptics->work);
error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
- DRV2667_STANDBY, 1);
+ DRV2667_STANDBY, DRV2667_STANDBY);
if (error)
dev_err(&haptics->client->dev,
"Failed to enter standby mode: %d\n", error);
@@ -415,7 +415,7 @@ static int __maybe_unused drv2667_suspend(struct device *dev)
if (haptics->input_dev->users) {
ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
- DRV2667_STANDBY, 1);
+ DRV2667_STANDBY, DRV2667_STANDBY);
if (ret) {
dev_err(dev, "Failed to set standby mode\n");
regulator_disable(haptics->regulator);
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
index c14b82709b0f..908b51089dee 100644
--- a/drivers/input/misc/soc_button_array.c
+++ b/drivers/input/misc/soc_button_array.c
@@ -17,6 +17,7 @@
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
+#include <linux/gpio.h>
#include <linux/platform_device.h>
/*
@@ -92,7 +93,7 @@ soc_button_device_create(struct platform_device *pdev,
continue;
gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
- if (gpio < 0)
+ if (!gpio_is_valid(gpio))
continue;
gpio_keys[n_buttons].type = info->event_type;
@@ -166,6 +167,11 @@ static int soc_button_probe(struct platform_device *pdev)
button_info = (struct soc_button_info *)id->driver_data;
+ if (gpiod_count(&pdev->dev, KBUILD_MODNAME) <= 0) {
+ dev_dbg(&pdev->dev, "no GPIO attached, ignoring...\n");
+ return -ENODEV;
+ }
+
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
diff --git a/drivers/input/misc/tps65218-pwrbutton.c b/drivers/input/misc/tps65218-pwrbutton.c
index 3273217ce80c..cc74a41bdb0d 100644
--- a/drivers/input/misc/tps65218-pwrbutton.c
+++ b/drivers/input/misc/tps65218-pwrbutton.c
@@ -150,12 +150,20 @@ static int tps6521x_pb_probe(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id tps6521x_pwrbtn_id_table[] = {
+ { "tps65218-pwrbutton", },
+ { "tps65217-pwrbutton", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, tps6521x_pwrbtn_id_table);
+
static struct platform_driver tps6521x_pb_driver = {
.probe = tps6521x_pb_probe,
.driver = {
.name = "tps6521x_pwrbutton",
.of_match_table = of_tps6521x_pb_match,
},
+ .id_table = tps6521x_pwrbtn_id_table,
};
module_platform_driver(tps6521x_pb_driver);
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 6d7de9bfed9a..328edc8c8786 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -1153,15 +1153,13 @@ static void alps_process_packet_v7(struct psmouse *psmouse)
alps_process_touchpad_packet_v7(psmouse);
}
-static unsigned char alps_get_pkt_id_ss4_v2(unsigned char *byte)
+static enum SS4_PACKET_ID alps_get_pkt_id_ss4_v2(unsigned char *byte)
{
- unsigned char pkt_id = SS4_PACKET_ID_IDLE;
+ enum SS4_PACKET_ID pkt_id = SS4_PACKET_ID_IDLE;
switch (byte[3] & 0x30) {
case 0x00:
- if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 &&
- (byte[3] & 0x88) == 0x08 && byte[4] == 0x10 &&
- byte[5] == 0x00) {
+ if (SS4_IS_IDLE_V2(byte)) {
pkt_id = SS4_PACKET_ID_IDLE;
} else {
pkt_id = SS4_PACKET_ID_ONE;
@@ -1188,7 +1186,7 @@ static int alps_decode_ss4_v2(struct alps_fields *f,
unsigned char *p, struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
- unsigned char pkt_id;
+ enum SS4_PACKET_ID pkt_id;
unsigned int no_data_x, no_data_y;
pkt_id = alps_get_pkt_id_ss4_v2(p);
@@ -1267,18 +1265,12 @@ static int alps_decode_ss4_v2(struct alps_fields *f,
break;
case SS4_PACKET_ID_STICK:
- if (!(priv->flags & ALPS_DUALPOINT)) {
- psmouse_warn(psmouse,
- "Rejected trackstick packet from non DualPoint device");
- } else {
- int x = (s8)(((p[0] & 1) << 7) | (p[1] & 0x7f));
- int y = (s8)(((p[3] & 1) << 7) | (p[2] & 0x7f));
- int pressure = (s8)(p[4] & 0x7f);
-
- input_report_rel(priv->dev2, REL_X, x);
- input_report_rel(priv->dev2, REL_Y, -y);
- input_report_abs(priv->dev2, ABS_PRESSURE, pressure);
- }
+ /*
+ * x, y, and pressure are decoded in
+ * alps_process_packet_ss4_v2()
+ */
+ f->first_mp = 0;
+ f->is_mp = 0;
break;
case SS4_PACKET_ID_IDLE:
@@ -1346,6 +1338,27 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse)
priv->multi_packet = 0;
+ /* Report trackstick */
+ if (alps_get_pkt_id_ss4_v2(packet) == SS4_PACKET_ID_STICK) {
+ if (!(priv->flags & ALPS_DUALPOINT)) {
+ psmouse_warn(psmouse,
+ "Rejected trackstick packet from non DualPoint device");
+ return;
+ }
+
+ input_report_rel(dev2, REL_X, SS4_TS_X_V2(packet));
+ input_report_rel(dev2, REL_Y, SS4_TS_Y_V2(packet));
+ input_report_abs(dev2, ABS_PRESSURE, SS4_TS_Z_V2(packet));
+
+ input_report_key(dev2, BTN_LEFT, f->ts_left);
+ input_report_key(dev2, BTN_RIGHT, f->ts_right);
+ input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
+
+ input_sync(dev2);
+ return;
+ }
+
+ /* Report touchpad */
alps_report_mt_data(psmouse, (f->fingers <= 4) ? f->fingers : 4);
input_mt_report_finger_count(dev, f->fingers);
@@ -1356,13 +1369,6 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse)
input_report_abs(dev, ABS_PRESSURE, f->pressure);
input_sync(dev);
-
- if (priv->flags & ALPS_DUALPOINT) {
- input_report_key(dev2, BTN_LEFT, f->ts_left);
- input_report_key(dev2, BTN_RIGHT, f->ts_right);
- input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
- input_sync(dev2);
- }
}
static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse)
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index b9417e2d7ad3..cde6f4bd8ea2 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -54,7 +54,15 @@ enum SS4_PACKET_ID {
#define SS4_MASK_NORMAL_BUTTONS 0x07
-#define SS4_1F_X_V2(_b) ((_b[0] & 0x0007) | \
+#define SS4_IS_IDLE_V2(_b) (((_b[0]) == 0x18) && \
+ ((_b[1]) == 0x10) && \
+ ((_b[2]) == 0x00) && \
+ ((_b[3] & 0x88) == 0x08) && \
+ ((_b[4]) == 0x10) && \
+ ((_b[5]) == 0x00) \
+ )
+
+#define SS4_1F_X_V2(_b) (((_b[0]) & 0x0007) | \
((_b[1] << 3) & 0x0078) | \
((_b[1] << 2) & 0x0380) | \
((_b[2] << 5) & 0x1C00) \
@@ -101,6 +109,18 @@ enum SS4_PACKET_ID {
#define SS4_IS_MF_CONTINUE(_b) ((_b[2] & 0x10) == 0x10)
#define SS4_IS_5F_DETECTED(_b) ((_b[2] & 0x10) == 0x10)
+#define SS4_TS_X_V2(_b) (s8)( \
+ ((_b[0] & 0x01) << 7) | \
+ (_b[1] & 0x7F) \
+ )
+
+#define SS4_TS_Y_V2(_b) (s8)( \
+ ((_b[3] & 0x01) << 7) | \
+ (_b[2] & 0x7F) \
+ )
+
+#define SS4_TS_Z_V2(_b) (s8)(_b[4] & 0x7F)
+
#define SS4_MFPACKET_NO_AX 8160 /* X-Coordinate value */
#define SS4_MFPACKET_NO_AY 4080 /* Y-Coordinate value */
@@ -146,7 +166,7 @@ struct alps_protocol_info {
* (aka command mode response) identifies the firmware minor version. This
* can be used to distinguish different hardware models which are not
* uniquely identifiable through their E7 responses.
- * @protocol_info: information about protcol used by the device.
+ * @protocol_info: information about protocol used by the device.
*
* Many (but not all) ALPS touchpads can be identified by looking at the
* values returned in the "E7 report" and/or the "EC report." This table
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index d15b33813021..fa598f7f4372 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -1093,19 +1093,18 @@ static int elan_probe(struct i2c_client *client,
if (error)
return error;
+ dev_info(&client->dev,
+ "Elan Touchpad: Module ID: 0x%04x, Firmware: 0x%04x, Sample: 0x%04x, IAP: 0x%04x\n",
+ data->product_id,
+ data->fw_version,
+ data->sm_version,
+ data->iap_version);
+
dev_dbg(&client->dev,
- "Elan Touchpad Information:\n"
- " Module product ID: 0x%04x\n"
- " Firmware Version: 0x%04x\n"
- " Sample Version: 0x%04x\n"
- " IAP Version: 0x%04x\n"
+ "Elan Touchpad Extra Information:\n"
" Max ABS X,Y: %d,%d\n"
" Width X,Y: %d,%d\n"
" Resolution X,Y: %d,%d (dots/mm)\n",
- data->product_id,
- data->fw_version,
- data->sm_version,
- data->iap_version,
data->max_x, data->max_y,
data->width_x, data->width_y,
data->x_res, data->y_res);
diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig
index 4c8a55857e00..30cc627a4f45 100644
--- a/drivers/input/rmi4/Kconfig
+++ b/drivers/input/rmi4/Kconfig
@@ -27,6 +27,27 @@ config RMI4_SPI
If unsure, say N.
+config RMI4_SMB
+ tristate "RMI4 SMB Support"
+ depends on RMI4_CORE && I2C
+ help
+ Say Y here if you want to support RMI4 devices connected to an SMB
+ bus.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the module will be
+ called rmi_smbus.
+
+config RMI4_F03
+ bool "RMI4 Function 03 (PS2 Guest)"
+ depends on RMI4_CORE && SERIO
+ help
+ Say Y here if you want to add support for RMI4 function 03.
+
+ Function 03 provides PS2 guest support for RMI4 devices. This
+ includes support for TrackPoints on TouchPads.
+
config RMI4_2D_SENSOR
bool
depends on RMI4_CORE
@@ -62,13 +83,34 @@ config RMI4_F30
Function 30 provides GPIO and LED support for RMI4 devices. This
includes support for buttons on TouchPads and ClickPads.
+config RMI4_F34
+ bool "RMI4 Function 34 (Device reflash)"
+ depends on RMI4_CORE
+ select FW_LOADER
+ help
+ Say Y here if you want to add support for RMI4 function 34.
+
+ Function 34 provides support for upgrading the firmware on the RMI4
+ device via the firmware loader interface. This is triggered using a
+ sysfs attribute.
+
config RMI4_F54
bool "RMI4 Function 54 (Analog diagnostics)"
depends on RMI4_CORE
depends on VIDEO_V4L2=y || (RMI4_CORE=m && VIDEO_V4L2=m)
select VIDEOBUF2_VMALLOC
+ select RMI4_F55
help
Say Y here if you want to add support for RMI4 function 54
Function 54 provides access to various diagnostic features in certain
RMI4 touch sensors.
+
+config RMI4_F55
+ bool "RMI4 Function 55 (Sensor tuning)"
+ depends on RMI4_CORE
+ help
+ Say Y here if you want to add support for RMI4 function 55
+
+ Function 55 provides access to the RMI4 touch sensor tuning
+ mechanism.
diff --git a/drivers/input/rmi4/Makefile b/drivers/input/rmi4/Makefile
index 0bafc8502c4b..9aaac3dd8613 100644
--- a/drivers/input/rmi4/Makefile
+++ b/drivers/input/rmi4/Makefile
@@ -4,11 +4,15 @@ rmi_core-y := rmi_bus.o rmi_driver.o rmi_f01.o
rmi_core-$(CONFIG_RMI4_2D_SENSOR) += rmi_2d_sensor.o
# Function drivers
+rmi_core-$(CONFIG_RMI4_F03) += rmi_f03.o
rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o
rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o
rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o
+rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_f34v7.o
rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o
+rmi_core-$(CONFIG_RMI4_F55) += rmi_f55.o
# Transports
obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o
obj-$(CONFIG_RMI4_SPI) += rmi_spi.o
+obj-$(CONFIG_RMI4_SMB) += rmi_smbus.o
diff --git a/drivers/input/rmi4/rmi_2d_sensor.c b/drivers/input/rmi4/rmi_2d_sensor.c
index e97bd7fabccc..07007ff8e29f 100644
--- a/drivers/input/rmi4/rmi_2d_sensor.c
+++ b/drivers/input/rmi4/rmi_2d_sensor.c
@@ -177,10 +177,12 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor)
sensor->dmax = DMAX * res_x;
}
- input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0);
- input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
- input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
- input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+ input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0);
+ input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
+ input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
+ input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+ input_set_abs_params(input, ABS_MT_TOOL_TYPE,
+ 0, MT_TOOL_MAX, 0, 0);
if (sensor->sensor_type == rmi_sensor_touchpad)
input_flags = INPUT_MT_POINTER;
diff --git a/drivers/input/rmi4/rmi_2d_sensor.h b/drivers/input/rmi4/rmi_2d_sensor.h
index 77fcdfef003c..c871bef4dac0 100644
--- a/drivers/input/rmi4/rmi_2d_sensor.h
+++ b/drivers/input/rmi4/rmi_2d_sensor.h
@@ -67,6 +67,8 @@ struct rmi_2d_sensor {
u8 report_rel;
u8 x_mm;
u8 y_mm;
+ enum rmi_reg_state dribble;
+ enum rmi_reg_state palm_detect;
};
int rmi_2d_sensor_of_probe(struct device *dev,
diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c
index ef8c747c35e7..1c40d94ca506 100644
--- a/drivers/input/rmi4/rmi_bus.c
+++ b/drivers/input/rmi4/rmi_bus.c
@@ -230,6 +230,9 @@ err_put_device:
void rmi_unregister_function(struct rmi_function *fn)
{
+ rmi_dbg(RMI_DEBUG_CORE, &fn->dev, "Unregistering F%02X.\n",
+ fn->fd.function_number);
+
device_del(&fn->dev);
of_node_put(fn->dev.of_node);
put_device(&fn->dev);
@@ -302,6 +305,9 @@ struct bus_type rmi_bus_type = {
static struct rmi_function_handler *fn_handlers[] = {
&rmi_f01_handler,
+#ifdef CONFIG_RMI4_F03
+ &rmi_f03_handler,
+#endif
#ifdef CONFIG_RMI4_F11
&rmi_f11_handler,
#endif
@@ -311,9 +317,15 @@ static struct rmi_function_handler *fn_handlers[] = {
#ifdef CONFIG_RMI4_F30
&rmi_f30_handler,
#endif
+#ifdef CONFIG_RMI4_F34
+ &rmi_f34_handler,
+#endif
#ifdef CONFIG_RMI4_F54
&rmi_f54_handler,
#endif
+#ifdef CONFIG_RMI4_F55
+ &rmi_f55_handler,
+#endif
};
static void __rmi_unregister_function_handlers(int start_idx)
diff --git a/drivers/input/rmi4/rmi_bus.h b/drivers/input/rmi4/rmi_bus.h
index 899579830536..b7625a9ac66a 100644
--- a/drivers/input/rmi4/rmi_bus.h
+++ b/drivers/input/rmi4/rmi_bus.h
@@ -105,6 +105,18 @@ rmi_get_platform_data(struct rmi_device *d)
bool rmi_is_physical_device(struct device *dev);
/**
+ * rmi_reset - reset a RMI4 device
+ * @d: Pointer to an RMI device
+ *
+ * Calls for a reset of each function implemented by a specific device.
+ * Returns 0 on success or a negative error code.
+ */
+static inline int rmi_reset(struct rmi_device *d)
+{
+ return d->driver->reset_handler(d);
+}
+
+/**
* rmi_read - read a single byte
* @d: Pointer to an RMI device
* @addr: The address to read from
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index 4a88312fbd25..11447ab1055c 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -17,6 +17,7 @@
#include <linux/bitmap.h>
#include <linux/delay.h>
#include <linux/fs.h>
+#include <linux/irq.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/of.h>
@@ -33,12 +34,22 @@
#define RMI_DEVICE_RESET_CMD 0x01
#define DEFAULT_RESET_DELAY_MS 100
-static void rmi_free_function_list(struct rmi_device *rmi_dev)
+void rmi_free_function_list(struct rmi_device *rmi_dev)
{
struct rmi_function *fn, *tmp;
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Freeing function list\n");
+
+ devm_kfree(&rmi_dev->dev, data->irq_memory);
+ data->irq_memory = NULL;
+ data->irq_status = NULL;
+ data->fn_irq_bits = NULL;
+ data->current_irq_mask = NULL;
+ data->new_irq_mask = NULL;
+
data->f01_container = NULL;
+ data->f34_container = NULL;
/* Doing it in the reverse order so F01 will be removed last */
list_for_each_entry_safe_reverse(fn, tmp,
@@ -133,7 +144,7 @@ static void process_one_interrupt(struct rmi_driver_data *data,
}
}
-int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
+static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
{
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
struct device *dev = &rmi_dev->dev;
@@ -143,7 +154,7 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
if (!data)
return 0;
- if (!rmi_dev->xport->attn_data) {
+ if (!data->attn_data.data) {
error = rmi_read_block(rmi_dev,
data->f01_container->fd.data_base_addr + 1,
data->irq_status, data->num_of_irq_regs);
@@ -178,7 +189,81 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
return 0;
}
-EXPORT_SYMBOL_GPL(rmi_process_interrupt_requests);
+
+void rmi_set_attn_data(struct rmi_device *rmi_dev, unsigned long irq_status,
+ void *data, size_t size)
+{
+ struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
+ struct rmi4_attn_data attn_data;
+ void *fifo_data;
+
+ if (!drvdata->enabled)
+ return;
+
+ fifo_data = kmemdup(data, size, GFP_ATOMIC);
+ if (!fifo_data)
+ return;
+
+ attn_data.irq_status = irq_status;
+ attn_data.size = size;
+ attn_data.data = fifo_data;
+
+ kfifo_put(&drvdata->attn_fifo, attn_data);
+}
+EXPORT_SYMBOL_GPL(rmi_set_attn_data);
+
+static irqreturn_t rmi_irq_fn(int irq, void *dev_id)
+{
+ struct rmi_device *rmi_dev = dev_id;
+ struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
+ struct rmi4_attn_data attn_data = {0};
+ int ret, count;
+
+ count = kfifo_get(&drvdata->attn_fifo, &attn_data);
+ if (count) {
+ *(drvdata->irq_status) = attn_data.irq_status;
+ drvdata->attn_data = attn_data;
+ }
+
+ ret = rmi_process_interrupt_requests(rmi_dev);
+ if (ret)
+ rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev,
+ "Failed to process interrupt request: %d\n", ret);
+
+ if (count)
+ kfree(attn_data.data);
+
+ if (!kfifo_is_empty(&drvdata->attn_fifo))
+ return rmi_irq_fn(irq, dev_id);
+
+ return IRQ_HANDLED;
+}
+
+static int rmi_irq_init(struct rmi_device *rmi_dev)
+{
+ struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ int irq_flags = irq_get_trigger_type(pdata->irq);
+ int ret;
+
+ if (!irq_flags)
+ irq_flags = IRQF_TRIGGER_LOW;
+
+ ret = devm_request_threaded_irq(&rmi_dev->dev, pdata->irq, NULL,
+ rmi_irq_fn, irq_flags | IRQF_ONESHOT,
+ dev_name(rmi_dev->xport->dev),
+ rmi_dev);
+ if (ret < 0) {
+ dev_err(&rmi_dev->dev, "Failed to register interrupt %d\n",
+ pdata->irq);
+
+ return ret;
+ }
+
+ data->enabled = true;
+
+ return 0;
+}
static int suspend_one_function(struct rmi_function *fn)
{
@@ -248,7 +333,7 @@ static int rmi_resume_functions(struct rmi_device *rmi_dev)
return 0;
}
-static int enable_sensor(struct rmi_device *rmi_dev)
+int rmi_enable_sensor(struct rmi_device *rmi_dev)
{
int retval = 0;
@@ -379,8 +464,8 @@ static int rmi_driver_reset_handler(struct rmi_device *rmi_dev)
return 0;
}
-int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
- u16 pdt_address)
+static int rmi_read_pdt_entry(struct rmi_device *rmi_dev,
+ struct pdt_entry *entry, u16 pdt_address)
{
u8 buf[RMI_PDT_ENTRY_SIZE];
int error;
@@ -403,7 +488,6 @@ int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
return 0;
}
-EXPORT_SYMBOL_GPL(rmi_read_pdt_entry);
static void rmi_driver_copy_pdt_to_fd(const struct pdt_entry *pdt,
struct rmi_function_descriptor *fd)
@@ -422,6 +506,7 @@ static void rmi_driver_copy_pdt_to_fd(const struct pdt_entry *pdt,
static int rmi_scan_pdt_page(struct rmi_device *rmi_dev,
int page,
+ int *empty_pages,
void *ctx,
int (*callback)(struct rmi_device *rmi_dev,
void *ctx,
@@ -449,20 +534,30 @@ static int rmi_scan_pdt_page(struct rmi_device *rmi_dev,
return retval;
}
- return (data->f01_bootloader_mode || addr == pdt_start) ?
+ /*
+ * Count number of empty PDT pages. If a gap of two pages
+ * or more is found, stop scanning.
+ */
+ if (addr == pdt_start)
+ ++*empty_pages;
+ else
+ *empty_pages = 0;
+
+ return (data->bootloader_mode || *empty_pages >= 2) ?
RMI_SCAN_DONE : RMI_SCAN_CONTINUE;
}
-static int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
- int (*callback)(struct rmi_device *rmi_dev,
- void *ctx,
- const struct pdt_entry *entry))
+int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
+ int (*callback)(struct rmi_device *rmi_dev,
+ void *ctx, const struct pdt_entry *entry))
{
int page;
+ int empty_pages = 0;
int retval = RMI_SCAN_DONE;
for (page = 0; page <= RMI4_MAX_PAGE; page++) {
- retval = rmi_scan_pdt_page(rmi_dev, page, ctx, callback);
+ retval = rmi_scan_pdt_page(rmi_dev, page, &empty_pages,
+ ctx, callback);
if (retval != RMI_SCAN_CONTINUE)
break;
}
@@ -600,7 +695,6 @@ free_struct_buff:
kfree(struct_buf);
return ret;
}
-EXPORT_SYMBOL_GPL(rmi_read_register_desc);
const struct rmi_register_desc_item *rmi_get_register_desc_item(
struct rmi_register_descriptor *rdesc, u16 reg)
@@ -616,7 +710,6 @@ const struct rmi_register_desc_item *rmi_get_register_desc_item(
return NULL;
}
-EXPORT_SYMBOL_GPL(rmi_get_register_desc_item);
size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc)
{
@@ -630,7 +723,6 @@ size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc)
}
return size;
}
-EXPORT_SYMBOL_GPL(rmi_register_desc_calc_size);
/* Compute the register offset relative to the base address */
int rmi_register_desc_calc_reg_offset(
@@ -648,7 +740,6 @@ int rmi_register_desc_calc_reg_offset(
}
return -1;
}
-EXPORT_SYMBOL_GPL(rmi_register_desc_calc_reg_offset);
bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
u8 subpacket)
@@ -657,51 +748,55 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
subpacket) == subpacket;
}
-/* Indicates that flash programming is enabled (bootloader mode). */
-#define RMI_F01_STATUS_BOOTLOADER(status) (!!((status) & 0x40))
-
-/*
- * Given the PDT entry for F01, read the device status register to determine
- * if we're stuck in bootloader mode or not.
- *
- */
static int rmi_check_bootloader_mode(struct rmi_device *rmi_dev,
const struct pdt_entry *pdt)
{
- int error;
- u8 device_status;
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ int ret;
+ u8 status;
- error = rmi_read(rmi_dev, pdt->data_base_addr + pdt->page_start,
- &device_status);
- if (error) {
- dev_err(&rmi_dev->dev,
- "Failed to read device status: %d.\n", error);
- return error;
+ if (pdt->function_number == 0x34 && pdt->function_version > 1) {
+ ret = rmi_read(rmi_dev, pdt->data_base_addr, &status);
+ if (ret) {
+ dev_err(&rmi_dev->dev,
+ "Failed to read F34 status: %d.\n", ret);
+ return ret;
+ }
+
+ if (status & BIT(7))
+ data->bootloader_mode = true;
+ } else if (pdt->function_number == 0x01) {
+ ret = rmi_read(rmi_dev, pdt->data_base_addr, &status);
+ if (ret) {
+ dev_err(&rmi_dev->dev,
+ "Failed to read F01 status: %d.\n", ret);
+ return ret;
+ }
+
+ if (status & BIT(6))
+ data->bootloader_mode = true;
}
- return RMI_F01_STATUS_BOOTLOADER(device_status);
+ return 0;
}
static int rmi_count_irqs(struct rmi_device *rmi_dev,
void *ctx, const struct pdt_entry *pdt)
{
- struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
int *irq_count = ctx;
+ int ret;
*irq_count += pdt->interrupt_source_count;
- if (pdt->function_number == 0x01) {
- data->f01_bootloader_mode =
- rmi_check_bootloader_mode(rmi_dev, pdt);
- if (data->f01_bootloader_mode)
- dev_warn(&rmi_dev->dev,
- "WARNING: RMI4 device is in bootloader mode!\n");
- }
+
+ ret = rmi_check_bootloader_mode(rmi_dev, pdt);
+ if (ret < 0)
+ return ret;
return RMI_SCAN_CONTINUE;
}
-static int rmi_initial_reset(struct rmi_device *rmi_dev,
- void *ctx, const struct pdt_entry *pdt)
+int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx,
+ const struct pdt_entry *pdt)
{
int error;
@@ -720,6 +815,7 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev,
return RMI_SCAN_DONE;
}
+ rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Sending reset\n");
error = rmi_write_block(rmi_dev, cmd_addr, &cmd_buf, 1);
if (error) {
dev_err(&rmi_dev->dev,
@@ -776,6 +872,8 @@ static int rmi_create_function(struct rmi_device *rmi_dev,
if (pdt->function_number == 0x01)
data->f01_container = fn;
+ else if (pdt->function_number == 0x34)
+ data->f34_container = fn;
list_add_tail(&fn->node, &data->function_list);
@@ -786,23 +884,95 @@ err_put_fn:
return error;
}
-int rmi_driver_suspend(struct rmi_device *rmi_dev)
+void rmi_enable_irq(struct rmi_device *rmi_dev, bool clear_wake)
{
- int retval = 0;
+ struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ int irq = pdata->irq;
+ int irq_flags;
+ int retval;
+
+ mutex_lock(&data->enabled_mutex);
+
+ if (data->enabled)
+ goto out;
+
+ enable_irq(irq);
+ data->enabled = true;
+ if (clear_wake && device_may_wakeup(rmi_dev->xport->dev)) {
+ retval = disable_irq_wake(irq);
+ if (!retval)
+ dev_warn(&rmi_dev->dev,
+ "Failed to disable irq for wake: %d\n",
+ retval);
+ }
+
+ /*
+ * Call rmi_process_interrupt_requests() after enabling irq,
+ * otherwise we may lose interrupt on edge-triggered systems.
+ */
+ irq_flags = irq_get_trigger_type(pdata->irq);
+ if (irq_flags & IRQ_TYPE_EDGE_BOTH)
+ rmi_process_interrupt_requests(rmi_dev);
+
+out:
+ mutex_unlock(&data->enabled_mutex);
+}
+
+void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake)
+{
+ struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ struct rmi4_attn_data attn_data = {0};
+ int irq = pdata->irq;
+ int retval, count;
+
+ mutex_lock(&data->enabled_mutex);
+
+ if (!data->enabled)
+ goto out;
+
+ data->enabled = false;
+ disable_irq(irq);
+ if (enable_wake && device_may_wakeup(rmi_dev->xport->dev)) {
+ retval = enable_irq_wake(irq);
+ if (!retval)
+ dev_warn(&rmi_dev->dev,
+ "Failed to enable irq for wake: %d\n",
+ retval);
+ }
+
+ /* make sure the fifo is clean */
+ while (!kfifo_is_empty(&data->attn_fifo)) {
+ count = kfifo_get(&data->attn_fifo, &attn_data);
+ if (count)
+ kfree(attn_data.data);
+ }
+
+out:
+ mutex_unlock(&data->enabled_mutex);
+}
+
+int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake)
+{
+ int retval;
retval = rmi_suspend_functions(rmi_dev);
if (retval)
dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
retval);
+ rmi_disable_irq(rmi_dev, enable_wake);
return retval;
}
EXPORT_SYMBOL_GPL(rmi_driver_suspend);
-int rmi_driver_resume(struct rmi_device *rmi_dev)
+int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake)
{
int retval;
+ rmi_enable_irq(rmi_dev, clear_wake);
+
retval = rmi_resume_functions(rmi_dev);
if (retval)
dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
@@ -816,6 +986,9 @@ static int rmi_driver_remove(struct device *dev)
{
struct rmi_device *rmi_dev = to_rmi_device(dev);
+ rmi_disable_irq(rmi_dev, false);
+
+ rmi_f34_remove_sysfs(rmi_dev);
rmi_free_function_list(rmi_dev);
return 0;
@@ -842,15 +1015,95 @@ static inline int rmi_driver_of_probe(struct device *dev,
}
#endif
+int rmi_probe_interrupts(struct rmi_driver_data *data)
+{
+ struct rmi_device *rmi_dev = data->rmi_dev;
+ struct device *dev = &rmi_dev->dev;
+ int irq_count;
+ size_t size;
+ int retval;
+
+ /*
+ * We need to count the IRQs and allocate their storage before scanning
+ * the PDT and creating the function entries, because adding a new
+ * function can trigger events that result in the IRQ related storage
+ * being accessed.
+ */
+ rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Counting IRQs.\n", __func__);
+ irq_count = 0;
+ data->bootloader_mode = false;
+
+ retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs);
+ if (retval < 0) {
+ dev_err(dev, "IRQ counting failed with code %d.\n", retval);
+ return retval;
+ }
+
+ if (data->bootloader_mode)
+ dev_warn(&rmi_dev->dev, "Device in bootloader mode.\n");
+
+ data->irq_count = irq_count;
+ data->num_of_irq_regs = (data->irq_count + 7) / 8;
+
+ size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long);
+ data->irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL);
+ if (!data->irq_memory) {
+ dev_err(dev, "Failed to allocate memory for irq masks.\n");
+ return retval;
+ }
+
+ data->irq_status = data->irq_memory + size * 0;
+ data->fn_irq_bits = data->irq_memory + size * 1;
+ data->current_irq_mask = data->irq_memory + size * 2;
+ data->new_irq_mask = data->irq_memory + size * 3;
+
+ return retval;
+}
+
+int rmi_init_functions(struct rmi_driver_data *data)
+{
+ struct rmi_device *rmi_dev = data->rmi_dev;
+ struct device *dev = &rmi_dev->dev;
+ int irq_count;
+ int retval;
+
+ irq_count = 0;
+ rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Creating functions.\n", __func__);
+ retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function);
+ if (retval < 0) {
+ dev_err(dev, "Function creation failed with code %d.\n",
+ retval);
+ goto err_destroy_functions;
+ }
+
+ if (!data->f01_container) {
+ dev_err(dev, "Missing F01 container!\n");
+ retval = -EINVAL;
+ goto err_destroy_functions;
+ }
+
+ retval = rmi_read_block(rmi_dev,
+ data->f01_container->fd.control_base_addr + 1,
+ data->current_irq_mask, data->num_of_irq_regs);
+ if (retval < 0) {
+ dev_err(dev, "%s: Failed to read current IRQ mask.\n",
+ __func__);
+ goto err_destroy_functions;
+ }
+
+ return 0;
+
+err_destroy_functions:
+ rmi_free_function_list(rmi_dev);
+ return retval;
+}
+
static int rmi_driver_probe(struct device *dev)
{
struct rmi_driver *rmi_driver;
struct rmi_driver_data *data;
struct rmi_device_platform_data *pdata;
struct rmi_device *rmi_dev;
- size_t size;
- void *irq_memory;
- int irq_count;
int retval;
rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Starting probe.\n",
@@ -916,35 +1169,12 @@ static int rmi_driver_probe(struct device *dev)
PDT_PROPERTIES_LOCATION, retval);
}
- /*
- * We need to count the IRQs and allocate their storage before scanning
- * the PDT and creating the function entries, because adding a new
- * function can trigger events that result in the IRQ related storage
- * being accessed.
- */
- rmi_dbg(RMI_DEBUG_CORE, dev, "Counting IRQs.\n");
- irq_count = 0;
- retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs);
- if (retval < 0) {
- dev_err(dev, "IRQ counting failed with code %d.\n", retval);
- goto err;
- }
- data->irq_count = irq_count;
- data->num_of_irq_regs = (data->irq_count + 7) / 8;
-
mutex_init(&data->irq_mutex);
+ mutex_init(&data->enabled_mutex);
- size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long);
- irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL);
- if (!irq_memory) {
- dev_err(dev, "Failed to allocate memory for irq masks.\n");
+ retval = rmi_probe_interrupts(data);
+ if (retval)
goto err;
- }
-
- data->irq_status = irq_memory + size * 0;
- data->fn_irq_bits = irq_memory + size * 1;
- data->current_irq_mask = irq_memory + size * 2;
- data->new_irq_mask = irq_memory + size * 3;
if (rmi_dev->xport->input) {
/*
@@ -961,36 +1191,20 @@ static int rmi_driver_probe(struct device *dev)
dev_err(dev, "%s: Failed to allocate input device.\n",
__func__);
retval = -ENOMEM;
- goto err_destroy_functions;
+ goto err;
}
rmi_driver_set_input_params(rmi_dev, data->input);
data->input->phys = devm_kasprintf(dev, GFP_KERNEL,
"%s/input0", dev_name(dev));
}
- irq_count = 0;
- rmi_dbg(RMI_DEBUG_CORE, dev, "Creating functions.");
- retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function);
- if (retval < 0) {
- dev_err(dev, "Function creation failed with code %d.\n",
- retval);
- goto err_destroy_functions;
- }
-
- if (!data->f01_container) {
- dev_err(dev, "Missing F01 container!\n");
- retval = -EINVAL;
- goto err_destroy_functions;
- }
+ retval = rmi_init_functions(data);
+ if (retval)
+ goto err;
- retval = rmi_read_block(rmi_dev,
- data->f01_container->fd.control_base_addr + 1,
- data->current_irq_mask, data->num_of_irq_regs);
- if (retval < 0) {
- dev_err(dev, "%s: Failed to read current IRQ mask.\n",
- __func__);
- goto err_destroy_functions;
- }
+ retval = rmi_f34_create_sysfs(rmi_dev);
+ if (retval)
+ goto err;
if (data->input) {
rmi_driver_set_input_name(rmi_dev, data->input);
@@ -1003,9 +1217,13 @@ static int rmi_driver_probe(struct device *dev)
}
}
+ retval = rmi_irq_init(rmi_dev);
+ if (retval < 0)
+ goto err_destroy_functions;
+
if (data->f01_container->dev.driver)
/* Driver already bound, so enable ATTN now. */
- return enable_sensor(rmi_dev);
+ return rmi_enable_sensor(rmi_dev);
return 0;
diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h
index 8dfbebe9bf86..24f8f764d171 100644
--- a/drivers/input/rmi4/rmi_driver.h
+++ b/drivers/input/rmi4/rmi_driver.h
@@ -51,9 +51,6 @@ struct pdt_entry {
u8 function_number;
};
-int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
- u16 pdt_address);
-
#define RMI_REG_DESC_PRESENSE_BITS (32 * BITS_PER_BYTE)
#define RMI_REG_DESC_SUBPACKET_BITS (37 * BITS_PER_BYTE)
@@ -95,12 +92,40 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
bool rmi_is_physical_driver(struct device_driver *);
int rmi_register_physical_driver(void);
void rmi_unregister_physical_driver(void);
+void rmi_free_function_list(struct rmi_device *rmi_dev);
+int rmi_enable_sensor(struct rmi_device *rmi_dev);
+int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
+ int (*callback)(struct rmi_device *rmi_dev, void *ctx,
+ const struct pdt_entry *entry));
+int rmi_probe_interrupts(struct rmi_driver_data *data);
+void rmi_enable_irq(struct rmi_device *rmi_dev, bool clear_wake);
+void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake);
+int rmi_init_functions(struct rmi_driver_data *data);
+int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx,
+ const struct pdt_entry *pdt);
char *rmi_f01_get_product_ID(struct rmi_function *fn);
+#ifdef CONFIG_RMI4_F34
+int rmi_f34_create_sysfs(struct rmi_device *rmi_dev);
+void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev);
+#else
+static inline int rmi_f34_create_sysfs(struct rmi_device *rmi_dev)
+{
+ return 0;
+}
+
+static inline void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev)
+{
+}
+#endif /* CONFIG_RMI_F34 */
+
extern struct rmi_function_handler rmi_f01_handler;
+extern struct rmi_function_handler rmi_f03_handler;
extern struct rmi_function_handler rmi_f11_handler;
extern struct rmi_function_handler rmi_f12_handler;
extern struct rmi_function_handler rmi_f30_handler;
+extern struct rmi_function_handler rmi_f34_handler;
extern struct rmi_function_handler rmi_f54_handler;
+extern struct rmi_function_handler rmi_f55_handler;
#endif
diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c
index b5d2dfc23bad..18baf4ceb940 100644
--- a/drivers/input/rmi4/rmi_f01.c
+++ b/drivers/input/rmi4/rmi_f01.c
@@ -62,6 +62,8 @@ struct f01_basic_properties {
#define RMI_F01_STATUS_CODE(status) ((status) & 0x0f)
/* The device has lost its configuration for some reason. */
#define RMI_F01_STATUS_UNCONFIGURED(status) (!!((status) & 0x80))
+/* The device is in bootloader mode */
+#define RMI_F01_STATUS_BOOTLOADER(status) ((status) & 0x40)
/* Control register bits */
@@ -326,12 +328,12 @@ static int rmi_f01_probe(struct rmi_function *fn)
}
switch (pdata->power_management.nosleep) {
- case RMI_F01_NOSLEEP_DEFAULT:
+ case RMI_REG_STATE_DEFAULT:
break;
- case RMI_F01_NOSLEEP_OFF:
+ case RMI_REG_STATE_OFF:
f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_NOSLEEP_BIT;
break;
- case RMI_F01_NOSLEEP_ON:
+ case RMI_REG_STATE_ON:
f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT;
break;
}
@@ -593,6 +595,10 @@ static int rmi_f01_attention(struct rmi_function *fn,
return error;
}
+ if (RMI_F01_STATUS_BOOTLOADER(device_status))
+ dev_warn(&fn->dev,
+ "Device in bootloader mode, please update firmware\n");
+
if (RMI_F01_STATUS_UNCONFIGURED(device_status)) {
dev_warn(&fn->dev, "Device reset detected.\n");
error = rmi_dev->driver->reset_handler(rmi_dev);
diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c
new file mode 100644
index 000000000000..8a7ca3e2f95e
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f03.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2015-2016 Red Hat
+ * Copyright (C) 2015 Lyude Paul <thatslyude@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/serio.h>
+#include <linux/notifier.h>
+#include "rmi_driver.h"
+
+#define RMI_F03_RX_DATA_OFB 0x01
+#define RMI_F03_OB_SIZE 2
+
+#define RMI_F03_OB_OFFSET 2
+#define RMI_F03_OB_DATA_OFFSET 1
+#define RMI_F03_OB_FLAG_TIMEOUT BIT(6)
+#define RMI_F03_OB_FLAG_PARITY BIT(7)
+
+#define RMI_F03_DEVICE_COUNT 0x07
+#define RMI_F03_BYTES_PER_DEVICE 0x07
+#define RMI_F03_BYTES_PER_DEVICE_SHIFT 4
+#define RMI_F03_QUEUE_LENGTH 0x0F
+
+struct f03_data {
+ struct rmi_function *fn;
+
+ struct serio *serio;
+
+ u8 device_count;
+ u8 rx_queue_length;
+};
+
+static int rmi_f03_pt_write(struct serio *id, unsigned char val)
+{
+ struct f03_data *f03 = id->port_data;
+ int error;
+
+ rmi_dbg(RMI_DEBUG_FN, &f03->fn->dev,
+ "%s: Wrote %.2hhx to PS/2 passthrough address",
+ __func__, val);
+
+ error = rmi_write(f03->fn->rmi_dev, f03->fn->fd.data_base_addr, val);
+ if (error) {
+ dev_err(&f03->fn->dev,
+ "%s: Failed to write to F03 TX register (%d).\n",
+ __func__, error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int rmi_f03_initialize(struct f03_data *f03)
+{
+ struct rmi_function *fn = f03->fn;
+ struct device *dev = &fn->dev;
+ int error;
+ u8 bytes_per_device;
+ u8 query1;
+ u8 query2[RMI_F03_DEVICE_COUNT * RMI_F03_BYTES_PER_DEVICE];
+ size_t query2_len;
+
+ error = rmi_read(fn->rmi_dev, fn->fd.query_base_addr, &query1);
+ if (error) {
+ dev_err(dev, "Failed to read query register (%d).\n", error);
+ return error;
+ }
+
+ f03->device_count = query1 & RMI_F03_DEVICE_COUNT;
+ bytes_per_device = (query1 >> RMI_F03_BYTES_PER_DEVICE_SHIFT) &
+ RMI_F03_BYTES_PER_DEVICE;
+
+ query2_len = f03->device_count * bytes_per_device;
+
+ /*
+ * The first generation of image sensors don't have a second part to
+ * their f03 query, as such we have to set some of these values manually
+ */
+ if (query2_len < 1) {
+ f03->device_count = 1;
+ f03->rx_queue_length = 7;
+ } else {
+ error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr + 1,
+ query2, query2_len);
+ if (error) {
+ dev_err(dev,
+ "Failed to read second set of query registers (%d).\n",
+ error);
+ return error;
+ }
+
+ f03->rx_queue_length = query2[0] & RMI_F03_QUEUE_LENGTH;
+ }
+
+ return 0;
+}
+
+static int rmi_f03_register_pt(struct f03_data *f03)
+{
+ struct serio *serio;
+
+ serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!serio)
+ return -ENOMEM;
+
+ serio->id.type = SERIO_8042;
+ serio->write = rmi_f03_pt_write;
+ serio->port_data = f03;
+
+ strlcpy(serio->name, "Synaptics RMI4 PS/2 pass-through",
+ sizeof(serio->name));
+ strlcpy(serio->phys, "synaptics-rmi4-pt/serio1",
+ sizeof(serio->phys));
+ serio->dev.parent = &f03->fn->dev;
+
+ f03->serio = serio;
+
+ serio_register_port(serio);
+
+ return 0;
+}
+
+static int rmi_f03_probe(struct rmi_function *fn)
+{
+ struct device *dev = &fn->dev;
+ struct f03_data *f03;
+ int error;
+
+ f03 = devm_kzalloc(dev, sizeof(struct f03_data), GFP_KERNEL);
+ if (!f03)
+ return -ENOMEM;
+
+ f03->fn = fn;
+
+ error = rmi_f03_initialize(f03);
+ if (error < 0)
+ return error;
+
+ if (f03->device_count != 1)
+ dev_warn(dev, "found %d devices on PS/2 passthrough",
+ f03->device_count);
+
+ dev_set_drvdata(dev, f03);
+
+ error = rmi_f03_register_pt(f03);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static int rmi_f03_config(struct rmi_function *fn)
+{
+ fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+
+ return 0;
+}
+
+static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
+{
+ struct rmi_device *rmi_dev = fn->rmi_dev;
+ struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
+ struct f03_data *f03 = dev_get_drvdata(&fn->dev);
+ u16 data_addr = fn->fd.data_base_addr;
+ const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
+ u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE];
+ u8 ob_status;
+ u8 ob_data;
+ unsigned int serio_flags;
+ int i;
+ int error;
+
+ if (!rmi_dev)
+ return -ENODEV;
+
+ if (drvdata->attn_data.data) {
+ /* First grab the data passed by the transport device */
+ if (drvdata->attn_data.size < ob_len) {
+ dev_warn(&fn->dev, "F03 interrupted, but data is missing!\n");
+ return 0;
+ }
+
+ memcpy(obs, drvdata->attn_data.data, ob_len);
+
+ drvdata->attn_data.data += ob_len;
+ drvdata->attn_data.size -= ob_len;
+ } else {
+ /* Grab all of the data registers, and check them for data */
+ error = rmi_read_block(fn->rmi_dev, data_addr + RMI_F03_OB_OFFSET,
+ &obs, ob_len);
+ if (error) {
+ dev_err(&fn->dev,
+ "%s: Failed to read F03 output buffers: %d\n",
+ __func__, error);
+ serio_interrupt(f03->serio, 0, SERIO_TIMEOUT);
+ return error;
+ }
+ }
+
+ for (i = 0; i < ob_len; i += RMI_F03_OB_SIZE) {
+ ob_status = obs[i];
+ ob_data = obs[i + RMI_F03_OB_DATA_OFFSET];
+ serio_flags = 0;
+
+ if (!(ob_status & RMI_F03_RX_DATA_OFB))
+ continue;
+
+ if (ob_status & RMI_F03_OB_FLAG_TIMEOUT)
+ serio_flags |= SERIO_TIMEOUT;
+ if (ob_status & RMI_F03_OB_FLAG_PARITY)
+ serio_flags |= SERIO_PARITY;
+
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev,
+ "%s: Received %.2hhx from PS2 guest T: %c P: %c\n",
+ __func__, ob_data,
+ serio_flags & SERIO_TIMEOUT ? 'Y' : 'N',
+ serio_flags & SERIO_PARITY ? 'Y' : 'N');
+
+ serio_interrupt(f03->serio, ob_data, serio_flags);
+ }
+
+ return 0;
+}
+
+static void rmi_f03_remove(struct rmi_function *fn)
+{
+ struct f03_data *f03 = dev_get_drvdata(&fn->dev);
+
+ serio_unregister_port(f03->serio);
+}
+
+struct rmi_function_handler rmi_f03_handler = {
+ .driver = {
+ .name = "rmi4_f03",
+ },
+ .func = 0x03,
+ .probe = rmi_f03_probe,
+ .config = rmi_f03_config,
+ .attention = rmi_f03_attention,
+ .remove = rmi_f03_remove,
+};
+
+MODULE_AUTHOR("Lyude Paul <thatslyude@gmail.com>");
+MODULE_DESCRIPTION("RMI F03 module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c
index f798f427a46f..bc5e37f30ac1 100644
--- a/drivers/input/rmi4/rmi_f11.c
+++ b/drivers/input/rmi4/rmi_f11.c
@@ -571,31 +571,48 @@ static inline u8 rmi_f11_parse_finger_state(const u8 *f_state, u8 n_finger)
static void rmi_f11_finger_handler(struct f11_data *f11,
struct rmi_2d_sensor *sensor,
- unsigned long *irq_bits, int num_irq_regs)
+ unsigned long *irq_bits, int num_irq_regs,
+ int size)
{
const u8 *f_state = f11->data.f_state;
u8 finger_state;
u8 i;
+ int abs_fingers;
+ int rel_fingers;
+ int abs_size = sensor->nbr_fingers * RMI_F11_ABS_BYTES;
int abs_bits = bitmap_and(f11->result_bits, irq_bits, f11->abs_mask,
num_irq_regs * 8);
int rel_bits = bitmap_and(f11->result_bits, irq_bits, f11->rel_mask,
num_irq_regs * 8);
- for (i = 0; i < sensor->nbr_fingers; i++) {
- /* Possible of having 4 fingers per f_statet register */
- finger_state = rmi_f11_parse_finger_state(f_state, i);
- if (finger_state == F11_RESERVED) {
- pr_err("Invalid finger state[%d]: 0x%02x", i,
- finger_state);
- continue;
- }
+ if (abs_bits) {
+ if (abs_size > size)
+ abs_fingers = size / RMI_F11_ABS_BYTES;
+ else
+ abs_fingers = sensor->nbr_fingers;
+
+ for (i = 0; i < abs_fingers; i++) {
+ /* Possible of having 4 fingers per f_state register */
+ finger_state = rmi_f11_parse_finger_state(f_state, i);
+ if (finger_state == F11_RESERVED) {
+ pr_err("Invalid finger state[%d]: 0x%02x", i,
+ finger_state);
+ continue;
+ }
- if (abs_bits)
rmi_f11_abs_pos_process(f11, sensor, &sensor->objs[i],
finger_state, i);
+ }
+ }
+
+ if (rel_bits) {
+ if ((abs_size + sensor->nbr_fingers * RMI_F11_REL_BYTES) > size)
+ rel_fingers = (size - abs_size) / RMI_F11_REL_BYTES;
+ else
+ rel_fingers = sensor->nbr_fingers;
- if (rel_bits)
+ for (i = 0; i < rel_fingers; i++)
rmi_f11_rel_pos_report(f11, i);
}
@@ -611,7 +628,7 @@ static void rmi_f11_finger_handler(struct f11_data *f11,
sensor->nbr_fingers,
sensor->dmax);
- for (i = 0; i < sensor->nbr_fingers; i++) {
+ for (i = 0; i < abs_fingers; i++) {
finger_state = rmi_f11_parse_finger_state(f_state, i);
if (finger_state == F11_RESERVED)
/* no need to send twice the error */
@@ -1062,8 +1079,8 @@ static int rmi_f11_initialize(struct rmi_function *fn)
rc = rmi_2d_sensor_of_probe(&fn->dev, &f11->sensor_pdata);
if (rc)
return rc;
- } else if (pdata->sensor_pdata) {
- f11->sensor_pdata = *pdata->sensor_pdata;
+ } else {
+ f11->sensor_pdata = pdata->sensor_pdata;
}
f11->rezero_wait_ms = f11->sensor_pdata.rezero_wait;
@@ -1124,6 +1141,8 @@ static int rmi_f11_initialize(struct rmi_function *fn)
sensor->topbuttonpad = f11->sensor_pdata.topbuttonpad;
sensor->kernel_tracking = f11->sensor_pdata.kernel_tracking;
sensor->dmax = f11->sensor_pdata.dmax;
+ sensor->dribble = f11->sensor_pdata.dribble;
+ sensor->palm_detect = f11->sensor_pdata.palm_detect;
if (f11->sens_query.has_physical_props) {
sensor->x_mm = f11->sens_query.x_sensor_size_mm;
@@ -1191,11 +1210,33 @@ static int rmi_f11_initialize(struct rmi_function *fn)
ctrl->ctrl0_11[RMI_F11_DELTA_Y_THRESHOLD] =
sensor->axis_align.delta_y_threshold;
- if (f11->sens_query.has_dribble)
- ctrl->ctrl0_11[0] = ctrl->ctrl0_11[0] & ~BIT(6);
+ if (f11->sens_query.has_dribble) {
+ switch (sensor->dribble) {
+ case RMI_REG_STATE_OFF:
+ ctrl->ctrl0_11[0] &= ~BIT(6);
+ break;
+ case RMI_REG_STATE_ON:
+ ctrl->ctrl0_11[0] |= BIT(6);
+ break;
+ case RMI_REG_STATE_DEFAULT:
+ default:
+ break;
+ }
+ }
- if (f11->sens_query.has_palm_det)
- ctrl->ctrl0_11[11] = ctrl->ctrl0_11[11] & ~BIT(0);
+ if (f11->sens_query.has_palm_det) {
+ switch (sensor->palm_detect) {
+ case RMI_REG_STATE_OFF:
+ ctrl->ctrl0_11[11] &= ~BIT(0);
+ break;
+ case RMI_REG_STATE_ON:
+ ctrl->ctrl0_11[11] |= BIT(0);
+ break;
+ case RMI_REG_STATE_DEFAULT:
+ default:
+ break;
+ }
+ }
rc = f11_write_control_regs(fn, &f11->sens_query,
&f11->dev_controls, fn->fd.query_base_addr);
@@ -1241,12 +1282,21 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
struct f11_data *f11 = dev_get_drvdata(&fn->dev);
u16 data_base_addr = fn->fd.data_base_addr;
int error;
+ int valid_bytes = f11->sensor.pkt_size;
- if (rmi_dev->xport->attn_data) {
- memcpy(f11->sensor.data_pkt, rmi_dev->xport->attn_data,
- f11->sensor.attn_size);
- rmi_dev->xport->attn_data += f11->sensor.attn_size;
- rmi_dev->xport->attn_size -= f11->sensor.attn_size;
+ if (drvdata->attn_data.data) {
+ /*
+ * The valid data in the attention report is less then
+ * expected. Only process the complete fingers.
+ */
+ if (f11->sensor.attn_size > drvdata->attn_data.size)
+ valid_bytes = drvdata->attn_data.size;
+ else
+ valid_bytes = f11->sensor.attn_size;
+ memcpy(f11->sensor.data_pkt, drvdata->attn_data.data,
+ valid_bytes);
+ drvdata->attn_data.data += f11->sensor.attn_size;
+ drvdata->attn_data.size -= f11->sensor.attn_size;
} else {
error = rmi_read_block(rmi_dev,
data_base_addr, f11->sensor.data_pkt,
@@ -1256,7 +1306,7 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
}
rmi_f11_finger_handler(f11, &f11->sensor, irq_bits,
- drvdata->num_of_irq_regs);
+ drvdata->num_of_irq_regs, valid_bytes);
return 0;
}
diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c
index 332c02f0b107..07aff4356fe0 100644
--- a/drivers/input/rmi4/rmi_f12.c
+++ b/drivers/input/rmi4/rmi_f12.c
@@ -26,9 +26,12 @@ enum rmi_f12_object_type {
RMI_F12_OBJECT_SMALL_OBJECT = 0x0D,
};
+#define F12_DATA1_BYTES_PER_OBJ 8
+
struct f12_data {
struct rmi_2d_sensor sensor;
struct rmi_2d_sensor_platform_data sensor_pdata;
+ bool has_dribble;
u16 data_addr;
@@ -68,10 +71,6 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
u8 buf[15];
int pitch_x = 0;
int pitch_y = 0;
- int clip_x_low = 0;
- int clip_x_high = 0;
- int clip_y_low = 0;
- int clip_y_high = 0;
int rx_receivers = 0;
int tx_receivers = 0;
int sensor_flags = 0;
@@ -124,7 +123,9 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
}
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: x low: %d x high: %d y low: %d y high: %d\n",
- __func__, clip_x_low, clip_x_high, clip_y_low, clip_y_high);
+ __func__,
+ sensor->axis_align.clip_x_low, sensor->axis_align.clip_x_high,
+ sensor->axis_align.clip_y_low, sensor->axis_align.clip_y_high);
if (rmi_register_desc_has_subpacket(item, 3)) {
rx_receivers = buf[offset];
@@ -146,12 +147,16 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
return 0;
}
-static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
+static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1, int size)
{
int i;
struct rmi_2d_sensor *sensor = &f12->sensor;
+ int objects = f12->data1->num_subpackets;
+
+ if ((f12->data1->num_subpackets * F12_DATA1_BYTES_PER_OBJ) > size)
+ objects = size / F12_DATA1_BYTES_PER_OBJ;
- for (i = 0; i < f12->data1->num_subpackets; i++) {
+ for (i = 0; i < objects; i++) {
struct rmi_2d_sensor_abs_object *obj = &sensor->objs[i];
obj->type = RMI_2D_OBJECT_NONE;
@@ -182,7 +187,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
rmi_2d_sensor_abs_process(sensor, obj, i);
- data1 += 8;
+ data1 += F12_DATA1_BYTES_PER_OBJ;
}
if (sensor->kernel_tracking)
@@ -192,7 +197,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
sensor->nbr_fingers,
sensor->dmax);
- for (i = 0; i < sensor->nbr_fingers; i++)
+ for (i = 0; i < objects; i++)
rmi_2d_sensor_abs_report(sensor, &sensor->objs[i], i);
}
@@ -201,14 +206,20 @@ static int rmi_f12_attention(struct rmi_function *fn,
{
int retval;
struct rmi_device *rmi_dev = fn->rmi_dev;
+ struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
struct f12_data *f12 = dev_get_drvdata(&fn->dev);
struct rmi_2d_sensor *sensor = &f12->sensor;
-
- if (rmi_dev->xport->attn_data) {
- memcpy(sensor->data_pkt, rmi_dev->xport->attn_data,
- sensor->attn_size);
- rmi_dev->xport->attn_data += sensor->attn_size;
- rmi_dev->xport->attn_size -= sensor->attn_size;
+ int valid_bytes = sensor->pkt_size;
+
+ if (drvdata->attn_data.data) {
+ if (sensor->attn_size > drvdata->attn_data.size)
+ valid_bytes = drvdata->attn_data.size;
+ else
+ valid_bytes = sensor->attn_size;
+ memcpy(sensor->data_pkt, drvdata->attn_data.data,
+ valid_bytes);
+ drvdata->attn_data.data += sensor->attn_size;
+ drvdata->attn_data.size -= sensor->attn_size;
} else {
retval = rmi_read_block(rmi_dev, f12->data_addr,
sensor->data_pkt, sensor->pkt_size);
@@ -221,19 +232,83 @@ static int rmi_f12_attention(struct rmi_function *fn,
if (f12->data1)
rmi_f12_process_objects(f12,
- &sensor->data_pkt[f12->data1_offset]);
+ &sensor->data_pkt[f12->data1_offset], valid_bytes);
input_mt_sync_frame(sensor->input);
return 0;
}
+static int rmi_f12_write_control_regs(struct rmi_function *fn)
+{
+ int ret;
+ const struct rmi_register_desc_item *item;
+ struct rmi_device *rmi_dev = fn->rmi_dev;
+ struct f12_data *f12 = dev_get_drvdata(&fn->dev);
+ int control_size;
+ char buf[3];
+ u16 control_offset = 0;
+ u8 subpacket_offset = 0;
+
+ if (f12->has_dribble
+ && (f12->sensor.dribble != RMI_REG_STATE_DEFAULT)) {
+ item = rmi_get_register_desc_item(&f12->control_reg_desc, 20);
+ if (item) {
+ control_offset = rmi_register_desc_calc_reg_offset(
+ &f12->control_reg_desc, 20);
+
+ /*
+ * The byte containing the EnableDribble bit will be
+ * in either byte 0 or byte 2 of control 20. Depending
+ * on the existence of subpacket 0. If control 20 is
+ * larger then 3 bytes, just read the first 3.
+ */
+ control_size = min(item->reg_size, 3UL);
+
+ ret = rmi_read_block(rmi_dev, fn->fd.control_base_addr
+ + control_offset, buf, control_size);
+ if (ret)
+ return ret;
+
+ if (rmi_register_desc_has_subpacket(item, 0))
+ subpacket_offset += 1;
+
+ switch (f12->sensor.dribble) {
+ case RMI_REG_STATE_OFF:
+ buf[subpacket_offset] &= ~BIT(2);
+ break;
+ case RMI_REG_STATE_ON:
+ buf[subpacket_offset] |= BIT(2);
+ break;
+ case RMI_REG_STATE_DEFAULT:
+ default:
+ break;
+ }
+
+ ret = rmi_write_block(rmi_dev,
+ fn->fd.control_base_addr + control_offset,
+ buf, control_size);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+
+}
+
static int rmi_f12_config(struct rmi_function *fn)
{
struct rmi_driver *drv = fn->rmi_dev->driver;
+ int ret;
drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+ ret = rmi_f12_write_control_regs(fn);
+ if (ret)
+ dev_warn(&fn->dev,
+ "Failed to write F12 control registers: %d\n", ret);
+
return 0;
}
@@ -247,7 +322,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
const struct rmi_register_desc_item *item;
struct rmi_2d_sensor *sensor;
struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
- struct rmi_transport_dev *xport = rmi_dev->xport;
+ struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
u16 data_offset = 0;
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s\n", __func__);
@@ -260,7 +335,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
}
++query_addr;
- if (!(buf & 0x1)) {
+ if (!(buf & BIT(0))) {
dev_err(&fn->dev,
"Behavior of F12 without register descriptors is undefined.\n");
return -ENODEV;
@@ -270,12 +345,14 @@ static int rmi_f12_probe(struct rmi_function *fn)
if (!f12)
return -ENOMEM;
+ f12->has_dribble = !!(buf & BIT(3));
+
if (fn->dev.of_node) {
ret = rmi_2d_sensor_of_probe(&fn->dev, &f12->sensor_pdata);
if (ret)
return ret;
- } else if (pdata->sensor_pdata) {
- f12->sensor_pdata = *pdata->sensor_pdata;
+ } else {
+ f12->sensor_pdata = pdata->sensor_pdata;
}
ret = rmi_read_register_desc(rmi_dev, query_addr,
@@ -318,6 +395,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
sensor->x_mm = f12->sensor_pdata.x_mm;
sensor->y_mm = f12->sensor_pdata.y_mm;
+ sensor->dribble = f12->sensor_pdata.dribble;
if (sensor->sensor_type == rmi_sensor_default)
sensor->sensor_type =
@@ -343,7 +421,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
* HID attention reports.
*/
item = rmi_get_register_desc_item(&f12->data_reg_desc, 0);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 1);
@@ -357,15 +435,15 @@ static int rmi_f12_probe(struct rmi_function *fn)
}
item = rmi_get_register_desc_item(&f12->data_reg_desc, 2);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 3);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 4);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 5);
@@ -377,22 +455,22 @@ static int rmi_f12_probe(struct rmi_function *fn)
}
item = rmi_get_register_desc_item(&f12->data_reg_desc, 6);
- if (item && !xport->attn_data) {
+ if (item && !drvdata->attn_data.data) {
f12->data6 = item;
f12->data6_offset = data_offset;
data_offset += item->reg_size;
}
item = rmi_get_register_desc_item(&f12->data_reg_desc, 7);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 8);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 9);
- if (item && !xport->attn_data) {
+ if (item && !drvdata->attn_data.data) {
f12->data9 = item;
f12->data9_offset = data_offset;
data_offset += item->reg_size;
@@ -401,27 +479,27 @@ static int rmi_f12_probe(struct rmi_function *fn)
}
item = rmi_get_register_desc_item(&f12->data_reg_desc, 10);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 11);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 12);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 13);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 14);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 15);
- if (item && !xport->attn_data) {
+ if (item && !drvdata->attn_data.data) {
f12->data15 = item;
f12->data15_offset = data_offset;
data_offset += item->reg_size;
diff --git a/drivers/input/rmi4/rmi_f30.c b/drivers/input/rmi4/rmi_f30.c
index 760aff1bc420..f4b491e3e0fd 100644
--- a/drivers/input/rmi4/rmi_f30.c
+++ b/drivers/input/rmi4/rmi_f30.c
@@ -99,6 +99,7 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
{
struct f30_data *f30 = dev_get_drvdata(&fn->dev);
struct rmi_device *rmi_dev = fn->rmi_dev;
+ struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
int retval;
int gpiled = 0;
int value = 0;
@@ -109,11 +110,15 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
return 0;
/* Read the gpi led data. */
- if (rmi_dev->xport->attn_data) {
- memcpy(f30->data_regs, rmi_dev->xport->attn_data,
+ if (drvdata->attn_data.data) {
+ if (drvdata->attn_data.size < f30->register_count) {
+ dev_warn(&fn->dev, "F30 interrupted, but data is missing\n");
+ return 0;
+ }
+ memcpy(f30->data_regs, drvdata->attn_data.data,
f30->register_count);
- rmi_dev->xport->attn_data += f30->register_count;
- rmi_dev->xport->attn_size -= f30->register_count;
+ drvdata->attn_data.data += f30->register_count;
+ drvdata->attn_data.size -= f30->register_count;
} else {
retval = rmi_read_block(rmi_dev, fn->fd.data_base_addr,
f30->data_regs, f30->register_count);
@@ -192,7 +197,7 @@ static int rmi_f30_config(struct rmi_function *fn)
rmi_get_platform_data(fn->rmi_dev);
int error;
- if (pdata->f30_data && pdata->f30_data->disable) {
+ if (pdata->f30_data.disable) {
drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
} else {
/* Write Control Register values back to device */
@@ -351,7 +356,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
f30->gpioled_key_map = (u16 *)map_memory;
pdata = rmi_get_platform_data(rmi_dev);
- if (pdata && f30->has_gpio) {
+ if (f30->has_gpio) {
button = BTN_LEFT;
for (i = 0; i < f30->gpioled_count; i++) {
if (rmi_f30_is_valid_button(i, f30->ctrl)) {
@@ -362,8 +367,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
* f30->has_mech_mouse_btns, but I am
* not sure, so use only the pdata info
*/
- if (pdata->f30_data &&
- pdata->f30_data->buttonpad)
+ if (pdata->f30_data.buttonpad)
break;
}
}
@@ -378,7 +382,7 @@ static int rmi_f30_probe(struct rmi_function *fn)
const struct rmi_device_platform_data *pdata =
rmi_get_platform_data(fn->rmi_dev);
- if (pdata->f30_data && pdata->f30_data->disable)
+ if (pdata->f30_data.disable)
return 0;
rc = rmi_f30_initialize(fn);
diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c
new file mode 100644
index 000000000000..9774dfbab9bb
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f34.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) 2007-2016, Synaptics Incorporated
+ * Copyright (C) 2016 Zodiac Inflight Innovations
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/firmware.h>
+#include <asm/unaligned.h>
+#include <asm/unaligned.h>
+#include <linux/bitops.h>
+
+#include "rmi_driver.h"
+#include "rmi_f34.h"
+
+static int rmi_f34_write_bootloader_id(struct f34_data *f34)
+{
+ struct rmi_function *fn = f34->fn;
+ struct rmi_device *rmi_dev = fn->rmi_dev;
+ u8 bootloader_id[F34_BOOTLOADER_ID_LEN];
+ int ret;
+
+ ret = rmi_read_block(rmi_dev, fn->fd.query_base_addr,
+ bootloader_id, sizeof(bootloader_id));
+ if (ret) {
+ dev_err(&fn->dev, "%s: Reading bootloader ID failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: writing bootloader id '%c%c'\n",
+ __func__, bootloader_id[0], bootloader_id[1]);
+
+ ret = rmi_write_block(rmi_dev,
+ fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET,
+ bootloader_id, sizeof(bootloader_id));
+ if (ret) {
+ dev_err(&fn->dev, "Failed to write bootloader ID: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rmi_f34_command(struct f34_data *f34, u8 command,
+ unsigned int timeout, bool write_bl_id)
+{
+ struct rmi_function *fn = f34->fn;
+ struct rmi_device *rmi_dev = fn->rmi_dev;
+ int ret;
+
+ if (write_bl_id) {
+ ret = rmi_f34_write_bootloader_id(f34);
+ if (ret)
+ return ret;
+ }
+
+ init_completion(&f34->v5.cmd_done);
+
+ ret = rmi_read(rmi_dev, f34->v5.ctrl_address, &f34->v5.status);
+ if (ret) {
+ dev_err(&f34->fn->dev,
+ "%s: Failed to read cmd register: %d (command %#02x)\n",
+ __func__, ret, command);
+ return ret;
+ }
+
+ f34->v5.status |= command & 0x0f;
+
+ ret = rmi_write(rmi_dev, f34->v5.ctrl_address, f34->v5.status);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "Failed to write F34 command %#02x: %d\n",
+ command, ret);
+ return ret;
+ }
+
+ if (!wait_for_completion_timeout(&f34->v5.cmd_done,
+ msecs_to_jiffies(timeout))) {
+
+ ret = rmi_read(rmi_dev, f34->v5.ctrl_address, &f34->v5.status);
+ if (ret) {
+ dev_err(&f34->fn->dev,
+ "%s: cmd %#02x timed out: %d\n",
+ __func__, command, ret);
+ return ret;
+ }
+
+ if (f34->v5.status & 0x7f) {
+ dev_err(&f34->fn->dev,
+ "%s: cmd %#02x timed out, status: %#02x\n",
+ __func__, command, f34->v5.status);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static int rmi_f34_attention(struct rmi_function *fn, unsigned long *irq_bits)
+{
+ struct f34_data *f34 = dev_get_drvdata(&fn->dev);
+ int ret;
+
+ if (f34->bl_version != 5)
+ return 0;
+
+ ret = rmi_read(f34->fn->rmi_dev, f34->v5.ctrl_address, &f34->v5.status);
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: status: %#02x, ret: %d\n",
+ __func__, f34->v5.status, ret);
+
+ if (!ret && !(f34->v5.status & 0x7f))
+ complete(&f34->v5.cmd_done);
+
+ return 0;
+}
+
+static int rmi_f34_write_blocks(struct f34_data *f34, const void *data,
+ int block_count, u8 command)
+{
+ struct rmi_function *fn = f34->fn;
+ struct rmi_device *rmi_dev = fn->rmi_dev;
+ u16 address = fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET;
+ u8 start_address[] = { 0, 0 };
+ int i;
+ int ret;
+
+ ret = rmi_write_block(rmi_dev, fn->fd.data_base_addr,
+ start_address, sizeof(start_address));
+ if (ret) {
+ dev_err(&fn->dev, "Failed to write initial zeros: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < block_count; i++) {
+ ret = rmi_write_block(rmi_dev, address,
+ data, f34->v5.block_size);
+ if (ret) {
+ dev_err(&fn->dev,
+ "failed to write block #%d: %d\n", i, ret);
+ return ret;
+ }
+
+ ret = rmi_f34_command(f34, command, F34_IDLE_WAIT_MS, false);
+ if (ret) {
+ dev_err(&fn->dev,
+ "Failed to write command for block #%d: %d\n",
+ i, ret);
+ return ret;
+ }
+
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "wrote block %d of %d\n",
+ i + 1, block_count);
+
+ data += f34->v5.block_size;
+ }
+
+ return 0;
+}
+
+static int rmi_f34_write_firmware(struct f34_data *f34, const void *data)
+{
+ return rmi_f34_write_blocks(f34, data, f34->v5.fw_blocks,
+ F34_WRITE_FW_BLOCK);
+}
+
+static int rmi_f34_write_config(struct f34_data *f34, const void *data)
+{
+ return rmi_f34_write_blocks(f34, data, f34->v5.config_blocks,
+ F34_WRITE_CONFIG_BLOCK);
+}
+
+int rmi_f34_enable_flash(struct f34_data *f34)
+{
+ return rmi_f34_command(f34, F34_ENABLE_FLASH_PROG,
+ F34_ENABLE_WAIT_MS, true);
+}
+
+static int rmi_f34_flash_firmware(struct f34_data *f34,
+ const struct rmi_f34_firmware *syn_fw)
+{
+ struct rmi_function *fn = f34->fn;
+ int ret;
+
+ if (syn_fw->image_size) {
+ dev_info(&fn->dev, "Erasing firmware...\n");
+ ret = rmi_f34_command(f34, F34_ERASE_ALL,
+ F34_ERASE_WAIT_MS, true);
+ if (ret)
+ return ret;
+
+ dev_info(&fn->dev, "Writing firmware (%d bytes)...\n",
+ syn_fw->image_size);
+ ret = rmi_f34_write_firmware(f34, syn_fw->data);
+ if (ret)
+ return ret;
+ }
+
+ if (syn_fw->config_size) {
+ /*
+ * We only need to erase config if we haven't updated
+ * firmware.
+ */
+ if (!syn_fw->image_size) {
+ dev_info(&fn->dev, "Erasing config...\n");
+ ret = rmi_f34_command(f34, F34_ERASE_CONFIG,
+ F34_ERASE_WAIT_MS, true);
+ if (ret)
+ return ret;
+ }
+
+ dev_info(&fn->dev, "Writing config (%d bytes)...\n",
+ syn_fw->config_size);
+ ret = rmi_f34_write_config(f34,
+ &syn_fw->data[syn_fw->image_size]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int rmi_f34_update_firmware(struct f34_data *f34, const struct firmware *fw)
+{
+ const struct rmi_f34_firmware *syn_fw;
+ int ret;
+
+ syn_fw = (const struct rmi_f34_firmware *)fw->data;
+ BUILD_BUG_ON(offsetof(struct rmi_f34_firmware, data) !=
+ F34_FW_IMAGE_OFFSET);
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "FW size:%d, checksum:%08x, image_size:%d, config_size:%d\n",
+ (int)fw->size,
+ le32_to_cpu(syn_fw->checksum),
+ le32_to_cpu(syn_fw->image_size),
+ le32_to_cpu(syn_fw->config_size));
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "FW bootloader_id:%02x, product_id:%.*s, info: %02x%02x\n",
+ syn_fw->bootloader_version,
+ (int)sizeof(syn_fw->product_id), syn_fw->product_id,
+ syn_fw->product_info[0], syn_fw->product_info[1]);
+
+ if (syn_fw->image_size &&
+ syn_fw->image_size != f34->v5.fw_blocks * f34->v5.block_size) {
+ dev_err(&f34->fn->dev,
+ "Bad firmware image: fw size %d, expected %d\n",
+ syn_fw->image_size,
+ f34->v5.fw_blocks * f34->v5.block_size);
+ ret = -EILSEQ;
+ goto out;
+ }
+
+ if (syn_fw->config_size &&
+ syn_fw->config_size != f34->v5.config_blocks * f34->v5.block_size) {
+ dev_err(&f34->fn->dev,
+ "Bad firmware image: config size %d, expected %d\n",
+ syn_fw->config_size,
+ f34->v5.config_blocks * f34->v5.block_size);
+ ret = -EILSEQ;
+ goto out;
+ }
+
+ if (syn_fw->image_size && !syn_fw->config_size) {
+ dev_err(&f34->fn->dev, "Bad firmware image: no config data\n");
+ ret = -EILSEQ;
+ goto out;
+ }
+
+ dev_info(&f34->fn->dev, "Firmware image OK\n");
+ mutex_lock(&f34->v5.flash_mutex);
+
+ ret = rmi_f34_flash_firmware(f34, syn_fw);
+
+ mutex_unlock(&f34->v5.flash_mutex);
+
+out:
+ return ret;
+}
+
+static int rmi_firmware_update(struct rmi_driver_data *data,
+ const struct firmware *fw)
+{
+ struct rmi_device *rmi_dev = data->rmi_dev;
+ struct device *dev = &rmi_dev->dev;
+ struct f34_data *f34;
+ int ret;
+
+ if (!data->f34_container) {
+ dev_warn(dev, "%s: No F34 present!\n", __func__);
+ return -EINVAL;
+ }
+
+ f34 = dev_get_drvdata(&data->f34_container->dev);
+
+ if (f34->bl_version == 7) {
+ if (data->pdt_props & HAS_BSR) {
+ dev_err(dev, "%s: LTS not supported\n", __func__);
+ return -ENODEV;
+ }
+ } else if (f34->bl_version != 5) {
+ dev_warn(dev, "F34 V%d not supported!\n",
+ data->f34_container->fd.function_version);
+ return -ENODEV;
+ }
+
+ /* Enter flash mode */
+ if (f34->bl_version == 7)
+ ret = rmi_f34v7_start_reflash(f34, fw);
+ else
+ ret = rmi_f34_enable_flash(f34);
+ if (ret)
+ return ret;
+
+ rmi_disable_irq(rmi_dev, false);
+
+ /* Tear down functions and re-probe */
+ rmi_free_function_list(rmi_dev);
+
+ ret = rmi_probe_interrupts(data);
+ if (ret)
+ return ret;
+
+ ret = rmi_init_functions(data);
+ if (ret)
+ return ret;
+
+ if (!data->bootloader_mode || !data->f34_container) {
+ dev_warn(dev, "%s: No F34 present or not in bootloader!\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ rmi_enable_irq(rmi_dev, false);
+
+ f34 = dev_get_drvdata(&data->f34_container->dev);
+
+ /* Perform firmware update */
+ if (f34->bl_version == 7)
+ ret = rmi_f34v7_do_reflash(f34, fw);
+ else
+ ret = rmi_f34_update_firmware(f34, fw);
+
+ dev_info(&f34->fn->dev, "Firmware update complete, status:%d\n", ret);
+
+ rmi_disable_irq(rmi_dev, false);
+
+ /* Re-probe */
+ rmi_dbg(RMI_DEBUG_FN, dev, "Re-probing device\n");
+ rmi_free_function_list(rmi_dev);
+
+ ret = rmi_scan_pdt(rmi_dev, NULL, rmi_initial_reset);
+ if (ret < 0)
+ dev_warn(dev, "RMI reset failed!\n");
+
+ ret = rmi_probe_interrupts(data);
+ if (ret)
+ return ret;
+
+ ret = rmi_init_functions(data);
+ if (ret)
+ return ret;
+
+ rmi_enable_irq(rmi_dev, false);
+
+ if (data->f01_container->dev.driver)
+ /* Driver already bound, so enable ATTN now. */
+ return rmi_enable_sensor(rmi_dev);
+
+ rmi_dbg(RMI_DEBUG_FN, dev, "%s complete\n", __func__);
+
+ return ret;
+}
+
+static int rmi_firmware_update(struct rmi_driver_data *data,
+ const struct firmware *fw);
+
+static ssize_t rmi_driver_update_fw_store(struct device *dev,
+ struct device_attribute *dattr,
+ const char *buf, size_t count)
+{
+ struct rmi_driver_data *data = dev_get_drvdata(dev);
+ char fw_name[NAME_MAX];
+ const struct firmware *fw;
+ size_t copy_count = count;
+ int ret;
+
+ if (count == 0 || count >= NAME_MAX)
+ return -EINVAL;
+
+ if (buf[count - 1] == '\0' || buf[count - 1] == '\n')
+ copy_count -= 1;
+
+ strncpy(fw_name, buf, copy_count);
+ fw_name[copy_count] = '\0';
+
+ ret = request_firmware(&fw, fw_name, dev);
+ if (ret)
+ return ret;
+
+ dev_info(dev, "Flashing %s\n", fw_name);
+
+ ret = rmi_firmware_update(data, fw);
+
+ release_firmware(fw);
+
+ return ret ?: count;
+}
+
+static DEVICE_ATTR(update_fw, 0200, NULL, rmi_driver_update_fw_store);
+
+static struct attribute *rmi_firmware_attrs[] = {
+ &dev_attr_update_fw.attr,
+ NULL
+};
+
+static struct attribute_group rmi_firmware_attr_group = {
+ .attrs = rmi_firmware_attrs,
+};
+
+static int rmi_f34_probe(struct rmi_function *fn)
+{
+ struct f34_data *f34;
+ unsigned char f34_queries[9];
+ bool has_config_id;
+ u8 version = fn->fd.function_version;
+ int ret;
+
+ f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL);
+ if (!f34)
+ return -ENOMEM;
+
+ f34->fn = fn;
+ dev_set_drvdata(&fn->dev, f34);
+
+ /* v5 code only supported version 0, try V7 probe */
+ if (version > 0)
+ return rmi_f34v7_probe(f34);
+ else if (version != 0)
+ return -ENODEV;
+
+ f34->bl_version = 5;
+
+ ret = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
+ f34_queries, sizeof(f34_queries));
+ if (ret) {
+ dev_err(&fn->dev, "%s: Failed to query properties\n",
+ __func__);
+ return ret;
+ }
+
+ snprintf(f34->bootloader_id, sizeof(f34->bootloader_id),
+ "%c%c", f34_queries[0], f34_queries[1]);
+
+ mutex_init(&f34->v5.flash_mutex);
+ init_completion(&f34->v5.cmd_done);
+
+ f34->v5.block_size = get_unaligned_le16(&f34_queries[3]);
+ f34->v5.fw_blocks = get_unaligned_le16(&f34_queries[5]);
+ f34->v5.config_blocks = get_unaligned_le16(&f34_queries[7]);
+ f34->v5.ctrl_address = fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET +
+ f34->v5.block_size;
+ has_config_id = f34_queries[2] & (1 << 2);
+
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Bootloader ID: %s\n",
+ f34->bootloader_id);
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Block size: %d\n",
+ f34->v5.block_size);
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "FW blocks: %d\n",
+ f34->v5.fw_blocks);
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "CFG blocks: %d\n",
+ f34->v5.config_blocks);
+
+ if (has_config_id) {
+ ret = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr,
+ f34_queries, sizeof(f34_queries));
+ if (ret) {
+ dev_err(&fn->dev, "Failed to read F34 config ID\n");
+ return ret;
+ }
+
+ snprintf(f34->configuration_id, sizeof(f34->configuration_id),
+ "%02x%02x%02x%02x",
+ f34_queries[0], f34_queries[1],
+ f34_queries[2], f34_queries[3]);
+
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Configuration ID: %s\n",
+ f34->configuration_id);
+ }
+
+ return 0;
+}
+
+int rmi_f34_create_sysfs(struct rmi_device *rmi_dev)
+{
+ return sysfs_create_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group);
+}
+
+void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev)
+{
+ sysfs_remove_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group);
+}
+
+struct rmi_function_handler rmi_f34_handler = {
+ .driver = {
+ .name = "rmi4_f34",
+ },
+ .func = 0x34,
+ .probe = rmi_f34_probe,
+ .attention = rmi_f34_attention,
+};
diff --git a/drivers/input/rmi4/rmi_f34.h b/drivers/input/rmi4/rmi_f34.h
new file mode 100644
index 000000000000..2c21056dc375
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f34.h
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2007-2016, Synaptics Incorporated
+ * Copyright (C) 2016 Zodiac Inflight Innovations
+ *
+ * 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.
+ */
+
+#ifndef _RMI_F34_H
+#define _RMI_F34_H
+
+/* F34 image file offsets. */
+#define F34_FW_IMAGE_OFFSET 0x100
+
+/* F34 register offsets. */
+#define F34_BLOCK_DATA_OFFSET 2
+
+/* F34 commands */
+#define F34_WRITE_FW_BLOCK 0x2
+#define F34_ERASE_ALL 0x3
+#define F34_READ_CONFIG_BLOCK 0x5
+#define F34_WRITE_CONFIG_BLOCK 0x6
+#define F34_ERASE_CONFIG 0x7
+#define F34_ENABLE_FLASH_PROG 0xf
+
+#define F34_STATUS_IN_PROGRESS 0xff
+#define F34_STATUS_IDLE 0x80
+
+#define F34_IDLE_WAIT_MS 500
+#define F34_ENABLE_WAIT_MS 300
+#define F34_ERASE_WAIT_MS 5000
+
+#define F34_BOOTLOADER_ID_LEN 2
+
+/* F34 V7 defines */
+#define V7_FLASH_STATUS_OFFSET 0
+#define V7_PARTITION_ID_OFFSET 1
+#define V7_BLOCK_NUMBER_OFFSET 2
+#define V7_TRANSFER_LENGTH_OFFSET 3
+#define V7_COMMAND_OFFSET 4
+#define V7_PAYLOAD_OFFSET 5
+#define V7_BOOTLOADER_ID_OFFSET 1
+
+#define IMAGE_HEADER_VERSION_10 0x10
+
+#define CONFIG_ID_SIZE 32
+#define PRODUCT_ID_SIZE 10
+
+#define ENABLE_WAIT_MS (1 * 1000)
+#define WRITE_WAIT_MS (3 * 1000)
+
+#define MIN_SLEEP_TIME_US 50
+#define MAX_SLEEP_TIME_US 100
+
+#define HAS_BSR BIT(5)
+#define HAS_CONFIG_ID BIT(3)
+#define HAS_GUEST_CODE BIT(6)
+#define HAS_DISP_CFG BIT(5)
+
+/* F34 V7 commands */
+#define CMD_V7_IDLE 0
+#define CMD_V7_ENTER_BL 1
+#define CMD_V7_READ 2
+#define CMD_V7_WRITE 3
+#define CMD_V7_ERASE 4
+#define CMD_V7_ERASE_AP 5
+#define CMD_V7_SENSOR_ID 6
+
+#define v7_CMD_IDLE 0
+#define v7_CMD_WRITE_FW 1
+#define v7_CMD_WRITE_CONFIG 2
+#define v7_CMD_WRITE_LOCKDOWN 3
+#define v7_CMD_WRITE_GUEST_CODE 4
+#define v7_CMD_READ_CONFIG 5
+#define v7_CMD_ERASE_ALL 6
+#define v7_CMD_ERASE_UI_FIRMWARE 7
+#define v7_CMD_ERASE_UI_CONFIG 8
+#define v7_CMD_ERASE_BL_CONFIG 9
+#define v7_CMD_ERASE_DISP_CONFIG 10
+#define v7_CMD_ERASE_FLASH_CONFIG 11
+#define v7_CMD_ERASE_GUEST_CODE 12
+#define v7_CMD_ENABLE_FLASH_PROG 13
+
+#define v7_UI_CONFIG_AREA 0
+#define v7_PM_CONFIG_AREA 1
+#define v7_BL_CONFIG_AREA 2
+#define v7_DP_CONFIG_AREA 3
+#define v7_FLASH_CONFIG_AREA 4
+
+/* F34 V7 partition IDs */
+#define BOOTLOADER_PARTITION 1
+#define DEVICE_CONFIG_PARTITION 2
+#define FLASH_CONFIG_PARTITION 3
+#define MANUFACTURING_BLOCK_PARTITION 4
+#define GUEST_SERIALIZATION_PARTITION 5
+#define GLOBAL_PARAMETERS_PARTITION 6
+#define CORE_CODE_PARTITION 7
+#define CORE_CONFIG_PARTITION 8
+#define GUEST_CODE_PARTITION 9
+#define DISPLAY_CONFIG_PARTITION 10
+
+/* F34 V7 container IDs */
+#define TOP_LEVEL_CONTAINER 0
+#define UI_CONTAINER 1
+#define UI_CONFIG_CONTAINER 2
+#define BL_CONTAINER 3
+#define BL_IMAGE_CONTAINER 4
+#define BL_CONFIG_CONTAINER 5
+#define BL_LOCKDOWN_INFO_CONTAINER 6
+#define PERMANENT_CONFIG_CONTAINER 7
+#define GUEST_CODE_CONTAINER 8
+#define BL_PROTOCOL_DESCRIPTOR_CONTAINER 9
+#define UI_PROTOCOL_DESCRIPTOR_CONTAINER 10
+#define RMI_SELF_DISCOVERY_CONTAINER 11
+#define RMI_PAGE_CONTENT_CONTAINER 12
+#define GENERAL_INFORMATION_CONTAINER 13
+#define DEVICE_CONFIG_CONTAINER 14
+#define FLASH_CONFIG_CONTAINER 15
+#define GUEST_SERIALIZATION_CONTAINER 16
+#define GLOBAL_PARAMETERS_CONTAINER 17
+#define CORE_CODE_CONTAINER 18
+#define CORE_CONFIG_CONTAINER 19
+#define DISPLAY_CONFIG_CONTAINER 20
+
+struct f34v7_query_1_7 {
+ u8 bl_minor_revision; /* query 1 */
+ u8 bl_major_revision;
+ __le32 bl_fw_id; /* query 2 */
+ u8 minimum_write_size; /* query 3 */
+ __le16 block_size;
+ __le16 flash_page_size;
+ __le16 adjustable_partition_area_size; /* query 4 */
+ __le16 flash_config_length; /* query 5 */
+ __le16 payload_length; /* query 6 */
+ u8 partition_support[4]; /* query 7 */
+} __packed;
+
+struct f34v7_data_1_5 {
+ u8 partition_id;
+ __le16 block_offset;
+ __le16 transfer_length;
+ u8 command;
+ u8 payload[2];
+} __packed;
+
+struct block_data {
+ const void *data;
+ int size;
+};
+
+struct partition_table {
+ u8 partition_id;
+ u8 byte_1_reserved;
+ __le16 partition_length;
+ __le16 start_physical_address;
+ __le16 partition_properties;
+} __packed;
+
+struct physical_address {
+ u16 ui_firmware;
+ u16 ui_config;
+ u16 dp_config;
+ u16 guest_code;
+};
+
+struct container_descriptor {
+ __le32 content_checksum;
+ __le16 container_id;
+ u8 minor_version;
+ u8 major_version;
+ u8 reserved_08;
+ u8 reserved_09;
+ u8 reserved_0a;
+ u8 reserved_0b;
+ u8 container_option_flags[4];
+ __le32 content_options_length;
+ __le32 content_options_address;
+ __le32 content_length;
+ __le32 content_address;
+} __packed;
+
+struct block_count {
+ u16 ui_firmware;
+ u16 ui_config;
+ u16 dp_config;
+ u16 fl_config;
+ u16 pm_config;
+ u16 bl_config;
+ u16 lockdown;
+ u16 guest_code;
+};
+
+struct image_header_10 {
+ __le32 checksum;
+ u8 reserved_04;
+ u8 reserved_05;
+ u8 minor_header_version;
+ u8 major_header_version;
+ u8 reserved_08;
+ u8 reserved_09;
+ u8 reserved_0a;
+ u8 reserved_0b;
+ __le32 top_level_container_start_addr;
+};
+
+struct image_metadata {
+ bool contains_firmware_id;
+ bool contains_bootloader;
+ bool contains_display_cfg;
+ bool contains_guest_code;
+ bool contains_flash_config;
+ unsigned int firmware_id;
+ unsigned int checksum;
+ unsigned int bootloader_size;
+ unsigned int display_cfg_offset;
+ unsigned char bl_version;
+ unsigned char product_id[PRODUCT_ID_SIZE + 1];
+ unsigned char cstmr_product_id[PRODUCT_ID_SIZE + 1];
+ struct block_data bootloader;
+ struct block_data ui_firmware;
+ struct block_data ui_config;
+ struct block_data dp_config;
+ struct block_data fl_config;
+ struct block_data bl_config;
+ struct block_data guest_code;
+ struct block_data lockdown;
+ struct block_count blkcount;
+ struct physical_address phyaddr;
+};
+
+struct register_offset {
+ u8 properties;
+ u8 properties_2;
+ u8 block_size;
+ u8 block_count;
+ u8 gc_block_count;
+ u8 flash_status;
+ u8 partition_id;
+ u8 block_number;
+ u8 transfer_length;
+ u8 flash_cmd;
+ u8 payload;
+};
+
+struct rmi_f34_firmware {
+ __le32 checksum;
+ u8 pad1[3];
+ u8 bootloader_version;
+ __le32 image_size;
+ __le32 config_size;
+ u8 product_id[10];
+ u8 product_info[2];
+ u8 pad2[228];
+ u8 data[];
+};
+
+struct f34v5_data {
+ u16 block_size;
+ u16 fw_blocks;
+ u16 config_blocks;
+ u16 ctrl_address;
+ u8 status;
+
+ struct completion cmd_done;
+ struct mutex flash_mutex;
+};
+
+struct f34v7_data {
+ bool has_display_cfg;
+ bool has_guest_code;
+ bool force_update;
+ bool in_bl_mode;
+ u8 *read_config_buf;
+ size_t read_config_buf_size;
+ u8 command;
+ u8 flash_status;
+ u16 block_size;
+ u16 config_block_count;
+ u16 config_size;
+ u16 config_area;
+ u16 flash_config_length;
+ u16 payload_length;
+ u8 partitions;
+ u16 partition_table_bytes;
+ bool new_partition_table;
+
+ struct register_offset off;
+ struct block_count blkcount;
+ struct physical_address phyaddr;
+ struct image_metadata img;
+
+ const void *config_data;
+ const void *image;
+};
+
+struct f34_data {
+ struct rmi_function *fn;
+
+ u8 bl_version;
+ unsigned char bootloader_id[5];
+ unsigned char configuration_id[CONFIG_ID_SIZE*2 + 1];
+
+ union {
+ struct f34v5_data v5;
+ struct f34v7_data v7;
+ };
+};
+
+int rmi_f34v7_start_reflash(struct f34_data *f34, const struct firmware *fw);
+int rmi_f34v7_do_reflash(struct f34_data *f34, const struct firmware *fw);
+int rmi_f34v7_probe(struct f34_data *f34);
+
+#endif /* _RMI_F34_H */
diff --git a/drivers/input/rmi4/rmi_f34v7.c b/drivers/input/rmi4/rmi_f34v7.c
new file mode 100644
index 000000000000..ca31f9539d9b
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f34v7.c
@@ -0,0 +1,1372 @@
+/*
+ * Copyright (c) 2016, Zodiac Inflight Innovations
+ * Copyright (c) 2007-2016, Synaptics Incorporated
+ * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
+ * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/firmware.h>
+#include <asm/unaligned.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include "rmi_driver.h"
+#include "rmi_f34.h"
+
+static int rmi_f34v7_read_flash_status(struct f34_data *f34)
+{
+ u8 status;
+ u8 command;
+ int ret;
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ f34->fn->fd.data_base_addr + f34->v7.off.flash_status,
+ &status,
+ sizeof(status));
+ if (ret < 0) {
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Failed to read flash status\n", __func__);
+ return ret;
+ }
+
+ f34->v7.in_bl_mode = status >> 7;
+ f34->v7.flash_status = status & 0x1f;
+
+ if (f34->v7.flash_status != 0x00) {
+ dev_err(&f34->fn->dev, "%s: status=%d, command=0x%02x\n",
+ __func__, f34->v7.flash_status, f34->v7.command);
+ }
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ f34->fn->fd.data_base_addr + f34->v7.off.flash_cmd,
+ &command,
+ sizeof(command));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to read flash command\n",
+ __func__);
+ return ret;
+ }
+
+ f34->v7.command = command;
+
+ return 0;
+}
+
+static int rmi_f34v7_wait_for_idle(struct f34_data *f34, int timeout_ms)
+{
+ int count = 0;
+ int timeout_count = ((timeout_ms * 1000) / MAX_SLEEP_TIME_US) + 1;
+
+ do {
+ usleep_range(MIN_SLEEP_TIME_US, MAX_SLEEP_TIME_US);
+
+ count++;
+
+ rmi_f34v7_read_flash_status(f34);
+
+ if ((f34->v7.command == v7_CMD_IDLE)
+ && (f34->v7.flash_status == 0x00)) {
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "Idle status detected\n");
+ return 0;
+ }
+ } while (count < timeout_count);
+
+ dev_err(&f34->fn->dev,
+ "%s: Timed out waiting for idle status\n", __func__);
+
+ return -ETIMEDOUT;
+}
+
+static int rmi_f34v7_write_command_single_transaction(struct f34_data *f34,
+ u8 cmd)
+{
+ int ret;
+ u8 base;
+ struct f34v7_data_1_5 data_1_5;
+
+ base = f34->fn->fd.data_base_addr;
+
+ memset(&data_1_5, 0, sizeof(data_1_5));
+
+ switch (cmd) {
+ case v7_CMD_ERASE_ALL:
+ data_1_5.partition_id = CORE_CODE_PARTITION;
+ data_1_5.command = CMD_V7_ERASE_AP;
+ break;
+ case v7_CMD_ERASE_UI_FIRMWARE:
+ data_1_5.partition_id = CORE_CODE_PARTITION;
+ data_1_5.command = CMD_V7_ERASE;
+ break;
+ case v7_CMD_ERASE_BL_CONFIG:
+ data_1_5.partition_id = GLOBAL_PARAMETERS_PARTITION;
+ data_1_5.command = CMD_V7_ERASE;
+ break;
+ case v7_CMD_ERASE_UI_CONFIG:
+ data_1_5.partition_id = CORE_CONFIG_PARTITION;
+ data_1_5.command = CMD_V7_ERASE;
+ break;
+ case v7_CMD_ERASE_DISP_CONFIG:
+ data_1_5.partition_id = DISPLAY_CONFIG_PARTITION;
+ data_1_5.command = CMD_V7_ERASE;
+ break;
+ case v7_CMD_ERASE_FLASH_CONFIG:
+ data_1_5.partition_id = FLASH_CONFIG_PARTITION;
+ data_1_5.command = CMD_V7_ERASE;
+ break;
+ case v7_CMD_ERASE_GUEST_CODE:
+ data_1_5.partition_id = GUEST_CODE_PARTITION;
+ data_1_5.command = CMD_V7_ERASE;
+ break;
+ case v7_CMD_ENABLE_FLASH_PROG:
+ data_1_5.partition_id = BOOTLOADER_PARTITION;
+ data_1_5.command = CMD_V7_ENTER_BL;
+ break;
+ }
+
+ data_1_5.payload[0] = f34->bootloader_id[0];
+ data_1_5.payload[1] = f34->bootloader_id[1];
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.partition_id,
+ &data_1_5, sizeof(data_1_5));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Failed to write single transaction command\n",
+ __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_write_command(struct f34_data *f34, u8 cmd)
+{
+ int ret;
+ u8 base;
+ u8 command;
+
+ base = f34->fn->fd.data_base_addr;
+
+ switch (cmd) {
+ case v7_CMD_WRITE_FW:
+ case v7_CMD_WRITE_CONFIG:
+ case v7_CMD_WRITE_GUEST_CODE:
+ command = CMD_V7_WRITE;
+ break;
+ case v7_CMD_READ_CONFIG:
+ command = CMD_V7_READ;
+ break;
+ case v7_CMD_ERASE_ALL:
+ command = CMD_V7_ERASE_AP;
+ break;
+ case v7_CMD_ERASE_UI_FIRMWARE:
+ case v7_CMD_ERASE_BL_CONFIG:
+ case v7_CMD_ERASE_UI_CONFIG:
+ case v7_CMD_ERASE_DISP_CONFIG:
+ case v7_CMD_ERASE_FLASH_CONFIG:
+ case v7_CMD_ERASE_GUEST_CODE:
+ command = CMD_V7_ERASE;
+ break;
+ case v7_CMD_ENABLE_FLASH_PROG:
+ command = CMD_V7_ENTER_BL;
+ break;
+ default:
+ dev_err(&f34->fn->dev, "%s: Invalid command 0x%02x\n",
+ __func__, cmd);
+ return -EINVAL;
+ }
+
+ f34->v7.command = command;
+
+ switch (cmd) {
+ case v7_CMD_ERASE_ALL:
+ case v7_CMD_ERASE_UI_FIRMWARE:
+ case v7_CMD_ERASE_BL_CONFIG:
+ case v7_CMD_ERASE_UI_CONFIG:
+ case v7_CMD_ERASE_DISP_CONFIG:
+ case v7_CMD_ERASE_FLASH_CONFIG:
+ case v7_CMD_ERASE_GUEST_CODE:
+ case v7_CMD_ENABLE_FLASH_PROG:
+ ret = rmi_f34v7_write_command_single_transaction(f34, cmd);
+ if (ret < 0)
+ return ret;
+ else
+ return 0;
+ default:
+ break;
+ }
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: writing cmd %02X\n",
+ __func__, command);
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.flash_cmd,
+ &command, sizeof(command));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to write flash command\n",
+ __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_write_partition_id(struct f34_data *f34, u8 cmd)
+{
+ int ret;
+ u8 base;
+ u8 partition;
+
+ base = f34->fn->fd.data_base_addr;
+
+ switch (cmd) {
+ case v7_CMD_WRITE_FW:
+ partition = CORE_CODE_PARTITION;
+ break;
+ case v7_CMD_WRITE_CONFIG:
+ case v7_CMD_READ_CONFIG:
+ if (f34->v7.config_area == v7_UI_CONFIG_AREA)
+ partition = CORE_CONFIG_PARTITION;
+ else if (f34->v7.config_area == v7_DP_CONFIG_AREA)
+ partition = DISPLAY_CONFIG_PARTITION;
+ else if (f34->v7.config_area == v7_PM_CONFIG_AREA)
+ partition = GUEST_SERIALIZATION_PARTITION;
+ else if (f34->v7.config_area == v7_BL_CONFIG_AREA)
+ partition = GLOBAL_PARAMETERS_PARTITION;
+ else if (f34->v7.config_area == v7_FLASH_CONFIG_AREA)
+ partition = FLASH_CONFIG_PARTITION;
+ break;
+ case v7_CMD_WRITE_GUEST_CODE:
+ partition = GUEST_CODE_PARTITION;
+ break;
+ case v7_CMD_ERASE_ALL:
+ partition = CORE_CODE_PARTITION;
+ break;
+ case v7_CMD_ERASE_BL_CONFIG:
+ partition = GLOBAL_PARAMETERS_PARTITION;
+ break;
+ case v7_CMD_ERASE_UI_CONFIG:
+ partition = CORE_CONFIG_PARTITION;
+ break;
+ case v7_CMD_ERASE_DISP_CONFIG:
+ partition = DISPLAY_CONFIG_PARTITION;
+ break;
+ case v7_CMD_ERASE_FLASH_CONFIG:
+ partition = FLASH_CONFIG_PARTITION;
+ break;
+ case v7_CMD_ERASE_GUEST_CODE:
+ partition = GUEST_CODE_PARTITION;
+ break;
+ case v7_CMD_ENABLE_FLASH_PROG:
+ partition = BOOTLOADER_PARTITION;
+ break;
+ default:
+ dev_err(&f34->fn->dev, "%s: Invalid command 0x%02x\n",
+ __func__, cmd);
+ return -EINVAL;
+ }
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.partition_id,
+ &partition, sizeof(partition));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to write partition ID\n",
+ __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_read_f34v7_partition_table(struct f34_data *f34)
+{
+ int ret;
+ u8 base;
+ __le16 length;
+ u16 block_number = 0;
+
+ base = f34->fn->fd.data_base_addr;
+
+ f34->v7.config_area = v7_FLASH_CONFIG_AREA;
+
+ ret = rmi_f34v7_write_partition_id(f34, v7_CMD_READ_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.block_number,
+ &block_number, sizeof(block_number));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to write block number\n",
+ __func__);
+ return ret;
+ }
+
+ put_unaligned_le16(f34->v7.flash_config_length, &length);
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.transfer_length,
+ &length, sizeof(length));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to write transfer length\n",
+ __func__);
+ return ret;
+ }
+
+ ret = rmi_f34v7_write_command(f34, v7_CMD_READ_CONFIG);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to write command\n",
+ __func__);
+ return ret;
+ }
+
+ ret = rmi_f34v7_wait_for_idle(f34, WRITE_WAIT_MS);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to wait for idle status\n",
+ __func__);
+ return ret;
+ }
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ base + f34->v7.off.payload,
+ f34->v7.read_config_buf,
+ f34->v7.partition_table_bytes);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to read block data\n",
+ __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void rmi_f34v7_parse_partition_table(struct f34_data *f34,
+ const void *partition_table,
+ struct block_count *blkcount,
+ struct physical_address *phyaddr)
+{
+ int i;
+ int index;
+ u16 partition_length;
+ u16 physical_address;
+ const struct partition_table *ptable;
+
+ for (i = 0; i < f34->v7.partitions; i++) {
+ index = i * 8 + 2;
+ ptable = partition_table + index;
+ partition_length = le16_to_cpu(ptable->partition_length);
+ physical_address = le16_to_cpu(ptable->start_physical_address);
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Partition entry %d: %*ph\n",
+ __func__, i, sizeof(struct partition_table), ptable);
+ switch (ptable->partition_id & 0x1f) {
+ case CORE_CODE_PARTITION:
+ blkcount->ui_firmware = partition_length;
+ phyaddr->ui_firmware = physical_address;
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Core code block count: %d\n",
+ __func__, blkcount->ui_firmware);
+ break;
+ case CORE_CONFIG_PARTITION:
+ blkcount->ui_config = partition_length;
+ phyaddr->ui_config = physical_address;
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Core config block count: %d\n",
+ __func__, blkcount->ui_config);
+ break;
+ case DISPLAY_CONFIG_PARTITION:
+ blkcount->dp_config = partition_length;
+ phyaddr->dp_config = physical_address;
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Display config block count: %d\n",
+ __func__, blkcount->dp_config);
+ break;
+ case FLASH_CONFIG_PARTITION:
+ blkcount->fl_config = partition_length;
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Flash config block count: %d\n",
+ __func__, blkcount->fl_config);
+ break;
+ case GUEST_CODE_PARTITION:
+ blkcount->guest_code = partition_length;
+ phyaddr->guest_code = physical_address;
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Guest code block count: %d\n",
+ __func__, blkcount->guest_code);
+ break;
+ case GUEST_SERIALIZATION_PARTITION:
+ blkcount->pm_config = partition_length;
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Guest serialization block count: %d\n",
+ __func__, blkcount->pm_config);
+ break;
+ case GLOBAL_PARAMETERS_PARTITION:
+ blkcount->bl_config = partition_length;
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Global parameters block count: %d\n",
+ __func__, blkcount->bl_config);
+ break;
+ case DEVICE_CONFIG_PARTITION:
+ blkcount->lockdown = partition_length;
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Device config block count: %d\n",
+ __func__, blkcount->lockdown);
+ break;
+ }
+ }
+}
+
+static int rmi_f34v7_read_queries_bl_version(struct f34_data *f34)
+{
+ int ret;
+ u8 base;
+ int offset;
+ u8 query_0;
+ struct f34v7_query_1_7 query_1_7;
+
+ base = f34->fn->fd.query_base_addr;
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ base,
+ &query_0,
+ sizeof(query_0));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Failed to read query 0\n", __func__);
+ return ret;
+ }
+
+ offset = (query_0 & 0x7) + 1;
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ base + offset,
+ &query_1_7,
+ sizeof(query_1_7));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to read queries 1 to 7\n",
+ __func__);
+ return ret;
+ }
+
+ f34->bootloader_id[0] = query_1_7.bl_minor_revision;
+ f34->bootloader_id[1] = query_1_7.bl_major_revision;
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "Bootloader V%d.%d\n",
+ f34->bootloader_id[1], f34->bootloader_id[0]);
+
+ return 0;
+}
+
+static int rmi_f34v7_read_queries(struct f34_data *f34)
+{
+ int ret;
+ int i, j;
+ u8 base;
+ int offset;
+ u8 *ptable;
+ u8 query_0;
+ struct f34v7_query_1_7 query_1_7;
+
+ base = f34->fn->fd.query_base_addr;
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ base,
+ &query_0,
+ sizeof(query_0));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Failed to read query 0\n", __func__);
+ return ret;
+ }
+
+ offset = (query_0 & 0x07) + 1;
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ base + offset,
+ &query_1_7,
+ sizeof(query_1_7));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to read queries 1 to 7\n",
+ __func__);
+ return ret;
+ }
+
+ f34->bootloader_id[0] = query_1_7.bl_minor_revision;
+ f34->bootloader_id[1] = query_1_7.bl_major_revision;
+
+ f34->v7.block_size = le16_to_cpu(query_1_7.block_size);
+ f34->v7.flash_config_length =
+ le16_to_cpu(query_1_7.flash_config_length);
+ f34->v7.payload_length = le16_to_cpu(query_1_7.payload_length);
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: f34->v7.block_size = %d\n",
+ __func__, f34->v7.block_size);
+
+ f34->v7.off.flash_status = V7_FLASH_STATUS_OFFSET;
+ f34->v7.off.partition_id = V7_PARTITION_ID_OFFSET;
+ f34->v7.off.block_number = V7_BLOCK_NUMBER_OFFSET;
+ f34->v7.off.transfer_length = V7_TRANSFER_LENGTH_OFFSET;
+ f34->v7.off.flash_cmd = V7_COMMAND_OFFSET;
+ f34->v7.off.payload = V7_PAYLOAD_OFFSET;
+
+ f34->v7.has_display_cfg = query_1_7.partition_support[1] & HAS_DISP_CFG;
+ f34->v7.has_guest_code =
+ query_1_7.partition_support[1] & HAS_GUEST_CODE;
+
+ if (query_0 & HAS_CONFIG_ID) {
+ char f34_ctrl[CONFIG_ID_SIZE];
+ int i = 0;
+ u8 *p = f34->configuration_id;
+ *p = '\0';
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ f34->fn->fd.control_base_addr,
+ f34_ctrl,
+ sizeof(f34_ctrl));
+ if (ret)
+ return ret;
+
+ /* Eat leading zeros */
+ while (i < sizeof(f34_ctrl) && !f34_ctrl[i])
+ i++;
+
+ for (; i < sizeof(f34_ctrl); i++)
+ p += snprintf(p, f34->configuration_id
+ + sizeof(f34->configuration_id) - p,
+ "%02X", f34_ctrl[i]);
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "Configuration ID: %s\n",
+ f34->configuration_id);
+ }
+
+ f34->v7.partitions = 0;
+ for (i = 0; i < sizeof(query_1_7.partition_support); i++)
+ for (j = 0; j < 8; j++)
+ if (query_1_7.partition_support[i] & (1 << j))
+ f34->v7.partitions++;
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: Supported partitions: %*ph\n",
+ __func__, sizeof(query_1_7.partition_support),
+ query_1_7.partition_support);
+
+
+ f34->v7.partition_table_bytes = f34->v7.partitions * 8 + 2;
+
+ f34->v7.read_config_buf = devm_kzalloc(&f34->fn->dev,
+ f34->v7.partition_table_bytes,
+ GFP_KERNEL);
+ if (!f34->v7.read_config_buf) {
+ f34->v7.read_config_buf_size = 0;
+ return -ENOMEM;
+ }
+
+ f34->v7.read_config_buf_size = f34->v7.partition_table_bytes;
+ ptable = f34->v7.read_config_buf;
+
+ ret = rmi_f34v7_read_f34v7_partition_table(f34);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to read partition table\n",
+ __func__);
+ return ret;
+ }
+
+ rmi_f34v7_parse_partition_table(f34, ptable,
+ &f34->v7.blkcount, &f34->v7.phyaddr);
+
+ return 0;
+}
+
+static int rmi_f34v7_check_ui_firmware_size(struct f34_data *f34)
+{
+ u16 block_count;
+
+ block_count = f34->v7.img.ui_firmware.size / f34->v7.block_size;
+
+ if (block_count != f34->v7.blkcount.ui_firmware) {
+ dev_err(&f34->fn->dev,
+ "UI firmware size mismatch: %d != %d\n",
+ block_count, f34->v7.blkcount.ui_firmware);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_check_ui_config_size(struct f34_data *f34)
+{
+ u16 block_count;
+
+ block_count = f34->v7.img.ui_config.size / f34->v7.block_size;
+
+ if (block_count != f34->v7.blkcount.ui_config) {
+ dev_err(&f34->fn->dev, "UI config size mismatch\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_check_dp_config_size(struct f34_data *f34)
+{
+ u16 block_count;
+
+ block_count = f34->v7.img.dp_config.size / f34->v7.block_size;
+
+ if (block_count != f34->v7.blkcount.dp_config) {
+ dev_err(&f34->fn->dev, "Display config size mismatch\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_check_guest_code_size(struct f34_data *f34)
+{
+ u16 block_count;
+
+ block_count = f34->v7.img.guest_code.size / f34->v7.block_size;
+ if (block_count != f34->v7.blkcount.guest_code) {
+ dev_err(&f34->fn->dev, "Guest code size mismatch\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_check_bl_config_size(struct f34_data *f34)
+{
+ u16 block_count;
+
+ block_count = f34->v7.img.bl_config.size / f34->v7.block_size;
+
+ if (block_count != f34->v7.blkcount.bl_config) {
+ dev_err(&f34->fn->dev, "Bootloader config size mismatch\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_erase_config(struct f34_data *f34)
+{
+ int ret;
+
+ dev_info(&f34->fn->dev, "Erasing config...\n");
+
+ switch (f34->v7.config_area) {
+ case v7_UI_CONFIG_AREA:
+ ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_UI_CONFIG);
+ if (ret < 0)
+ return ret;
+ break;
+ case v7_DP_CONFIG_AREA:
+ ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_DISP_CONFIG);
+ if (ret < 0)
+ return ret;
+ break;
+ case v7_BL_CONFIG_AREA:
+ ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_BL_CONFIG);
+ if (ret < 0)
+ return ret;
+ break;
+ }
+
+ ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static int rmi_f34v7_erase_guest_code(struct f34_data *f34)
+{
+ int ret;
+
+ dev_info(&f34->fn->dev, "Erasing guest code...\n");
+
+ ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_GUEST_CODE);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int rmi_f34v7_erase_all(struct f34_data *f34)
+{
+ int ret;
+
+ dev_info(&f34->fn->dev, "Erasing firmware...\n");
+
+ ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_UI_FIRMWARE);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+ if (ret < 0)
+ return ret;
+
+ f34->v7.config_area = v7_UI_CONFIG_AREA;
+ ret = rmi_f34v7_erase_config(f34);
+ if (ret < 0)
+ return ret;
+
+ if (f34->v7.has_display_cfg) {
+ f34->v7.config_area = v7_DP_CONFIG_AREA;
+ ret = rmi_f34v7_erase_config(f34);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (f34->v7.new_partition_table && f34->v7.has_guest_code) {
+ ret = rmi_f34v7_erase_guest_code(f34);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_read_f34v7_blocks(struct f34_data *f34, u16 block_cnt,
+ u8 command)
+{
+ int ret;
+ u8 base;
+ __le16 length;
+ u16 transfer;
+ u16 max_transfer;
+ u16 remaining = block_cnt;
+ u16 block_number = 0;
+ u16 index = 0;
+
+ base = f34->fn->fd.data_base_addr;
+
+ ret = rmi_f34v7_write_partition_id(f34, command);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.block_number,
+ &block_number, sizeof(block_number));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to write block number\n",
+ __func__);
+ return ret;
+ }
+
+ max_transfer = min(f34->v7.payload_length,
+ (u16)(PAGE_SIZE / f34->v7.block_size));
+
+ do {
+ transfer = min(remaining, max_transfer);
+ put_unaligned_le16(transfer, &length);
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.transfer_length,
+ &length, sizeof(length));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Write transfer length fail (%d remaining)\n",
+ __func__, remaining);
+ return ret;
+ }
+
+ ret = rmi_f34v7_write_command(f34, command);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Wait for idle failed (%d blks remaining)\n",
+ __func__, remaining);
+ return ret;
+ }
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ base + f34->v7.off.payload,
+ &f34->v7.read_config_buf[index],
+ transfer * f34->v7.block_size);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Read block failed (%d blks remaining)\n",
+ __func__, remaining);
+ return ret;
+ }
+
+ index += (transfer * f34->v7.block_size);
+ remaining -= transfer;
+ } while (remaining);
+
+ return 0;
+}
+
+static int rmi_f34v7_write_f34v7_blocks(struct f34_data *f34,
+ const void *block_ptr, u16 block_cnt,
+ u8 command)
+{
+ int ret;
+ u8 base;
+ __le16 length;
+ u16 transfer;
+ u16 max_transfer;
+ u16 remaining = block_cnt;
+ u16 block_number = 0;
+
+ base = f34->fn->fd.data_base_addr;
+
+ ret = rmi_f34v7_write_partition_id(f34, command);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.block_number,
+ &block_number, sizeof(block_number));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to write block number\n",
+ __func__);
+ return ret;
+ }
+
+ if (f34->v7.payload_length > (PAGE_SIZE / f34->v7.block_size))
+ max_transfer = PAGE_SIZE / f34->v7.block_size;
+ else
+ max_transfer = f34->v7.payload_length;
+
+ do {
+ transfer = min(remaining, max_transfer);
+ put_unaligned_le16(transfer, &length);
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.transfer_length,
+ &length, sizeof(length));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Write transfer length fail (%d remaining)\n",
+ __func__, remaining);
+ return ret;
+ }
+
+ ret = rmi_f34v7_write_command(f34, command);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.payload,
+ block_ptr, transfer * f34->v7.block_size);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Failed writing data (%d blks remaining)\n",
+ __func__, remaining);
+ return ret;
+ }
+
+ ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Failed wait for idle (%d blks remaining)\n",
+ __func__, remaining);
+ return ret;
+ }
+
+ block_ptr += (transfer * f34->v7.block_size);
+ remaining -= transfer;
+ } while (remaining);
+
+ return 0;
+}
+
+static int rmi_f34v7_write_config(struct f34_data *f34)
+{
+ return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.config_data,
+ f34->v7.config_block_count,
+ v7_CMD_WRITE_CONFIG);
+}
+
+static int rmi_f34v7_write_ui_config(struct f34_data *f34)
+{
+ f34->v7.config_area = v7_UI_CONFIG_AREA;
+ f34->v7.config_data = f34->v7.img.ui_config.data;
+ f34->v7.config_size = f34->v7.img.ui_config.size;
+ f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size;
+
+ return rmi_f34v7_write_config(f34);
+}
+
+static int rmi_f34v7_write_dp_config(struct f34_data *f34)
+{
+ f34->v7.config_area = v7_DP_CONFIG_AREA;
+ f34->v7.config_data = f34->v7.img.dp_config.data;
+ f34->v7.config_size = f34->v7.img.dp_config.size;
+ f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size;
+
+ return rmi_f34v7_write_config(f34);
+}
+
+static int rmi_f34v7_write_guest_code(struct f34_data *f34)
+{
+ return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.img.guest_code.data,
+ f34->v7.img.guest_code.size /
+ f34->v7.block_size,
+ v7_CMD_WRITE_GUEST_CODE);
+}
+
+static int rmi_f34v7_write_flash_config(struct f34_data *f34)
+{
+ int ret;
+
+ f34->v7.config_area = v7_FLASH_CONFIG_AREA;
+ f34->v7.config_data = f34->v7.img.fl_config.data;
+ f34->v7.config_size = f34->v7.img.fl_config.size;
+ f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size;
+
+ if (f34->v7.config_block_count != f34->v7.blkcount.fl_config) {
+ dev_err(&f34->fn->dev, "%s: Flash config size mismatch\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_FLASH_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Erase flash config command written\n", __func__);
+
+ ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_f34v7_write_config(f34);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int rmi_f34v7_write_partition_table(struct f34_data *f34)
+{
+ u16 block_count;
+ int ret;
+
+ block_count = f34->v7.blkcount.bl_config;
+ f34->v7.config_area = v7_BL_CONFIG_AREA;
+ f34->v7.config_size = f34->v7.block_size * block_count;
+ devm_kfree(&f34->fn->dev, f34->v7.read_config_buf);
+ f34->v7.read_config_buf = devm_kzalloc(&f34->fn->dev,
+ f34->v7.config_size, GFP_KERNEL);
+ if (!f34->v7.read_config_buf) {
+ f34->v7.read_config_buf_size = 0;
+ return -ENOMEM;
+ }
+
+ f34->v7.read_config_buf_size = f34->v7.config_size;
+
+ ret = rmi_f34v7_read_f34v7_blocks(f34, block_count, v7_CMD_READ_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_f34v7_erase_config(f34);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_f34v7_write_flash_config(f34);
+ if (ret < 0)
+ return ret;
+
+ f34->v7.config_area = v7_BL_CONFIG_AREA;
+ f34->v7.config_data = f34->v7.read_config_buf;
+ f34->v7.config_size = f34->v7.img.bl_config.size;
+ f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size;
+
+ ret = rmi_f34v7_write_config(f34);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int rmi_f34v7_write_firmware(struct f34_data *f34)
+{
+ u16 blk_count;
+
+ blk_count = f34->v7.img.ui_firmware.size / f34->v7.block_size;
+
+ return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.img.ui_firmware.data,
+ blk_count, v7_CMD_WRITE_FW);
+}
+
+static void rmi_f34v7_compare_partition_tables(struct f34_data *f34)
+{
+ if (f34->v7.phyaddr.ui_firmware != f34->v7.img.phyaddr.ui_firmware) {
+ f34->v7.new_partition_table = true;
+ return;
+ }
+
+ if (f34->v7.phyaddr.ui_config != f34->v7.img.phyaddr.ui_config) {
+ f34->v7.new_partition_table = true;
+ return;
+ }
+
+ if (f34->v7.has_display_cfg &&
+ f34->v7.phyaddr.dp_config != f34->v7.img.phyaddr.dp_config) {
+ f34->v7.new_partition_table = true;
+ return;
+ }
+
+ if (f34->v7.has_guest_code &&
+ f34->v7.phyaddr.guest_code != f34->v7.img.phyaddr.guest_code) {
+ f34->v7.new_partition_table = true;
+ return;
+ }
+
+ f34->v7.new_partition_table = false;
+}
+
+static void rmi_f34v7_parse_img_header_10_bl_container(struct f34_data *f34,
+ const void *image)
+{
+ int i;
+ int num_of_containers;
+ unsigned int addr;
+ unsigned int container_id;
+ unsigned int length;
+ const void *content;
+ const struct container_descriptor *descriptor;
+
+ num_of_containers = f34->v7.img.bootloader.size / 4 - 1;
+
+ for (i = 1; i <= num_of_containers; i++) {
+ addr = get_unaligned_le32(f34->v7.img.bootloader.data + i * 4);
+ descriptor = image + addr;
+ container_id = le16_to_cpu(descriptor->container_id);
+ content = image + le32_to_cpu(descriptor->content_address);
+ length = le32_to_cpu(descriptor->content_length);
+ switch (container_id) {
+ case BL_CONFIG_CONTAINER:
+ case GLOBAL_PARAMETERS_CONTAINER:
+ f34->v7.img.bl_config.data = content;
+ f34->v7.img.bl_config.size = length;
+ break;
+ case BL_LOCKDOWN_INFO_CONTAINER:
+ case DEVICE_CONFIG_CONTAINER:
+ f34->v7.img.lockdown.data = content;
+ f34->v7.img.lockdown.size = length;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void rmi_f34v7_parse_image_header_10(struct f34_data *f34)
+{
+ unsigned int i;
+ unsigned int num_of_containers;
+ unsigned int addr;
+ unsigned int offset;
+ unsigned int container_id;
+ unsigned int length;
+ const void *image = f34->v7.image;
+ const u8 *content;
+ const struct container_descriptor *descriptor;
+ const struct image_header_10 *header = image;
+
+ f34->v7.img.checksum = le32_to_cpu(header->checksum);
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: f34->v7.img.checksum=%X\n",
+ __func__, f34->v7.img.checksum);
+
+ /* address of top level container */
+ offset = le32_to_cpu(header->top_level_container_start_addr);
+ descriptor = image + offset;
+
+ /* address of top level container content */
+ offset = le32_to_cpu(descriptor->content_address);
+ num_of_containers = le32_to_cpu(descriptor->content_length) / 4;
+
+ for (i = 0; i < num_of_containers; i++) {
+ addr = get_unaligned_le32(image + offset);
+ offset += 4;
+ descriptor = image + addr;
+ container_id = le16_to_cpu(descriptor->container_id);
+ content = image + le32_to_cpu(descriptor->content_address);
+ length = le32_to_cpu(descriptor->content_length);
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: container_id=%d, length=%d\n", __func__,
+ container_id, length);
+
+ switch (container_id) {
+ case UI_CONTAINER:
+ case CORE_CODE_CONTAINER:
+ f34->v7.img.ui_firmware.data = content;
+ f34->v7.img.ui_firmware.size = length;
+ break;
+ case UI_CONFIG_CONTAINER:
+ case CORE_CONFIG_CONTAINER:
+ f34->v7.img.ui_config.data = content;
+ f34->v7.img.ui_config.size = length;
+ break;
+ case BL_CONTAINER:
+ f34->v7.img.bl_version = *content;
+ f34->v7.img.bootloader.data = content;
+ f34->v7.img.bootloader.size = length;
+ rmi_f34v7_parse_img_header_10_bl_container(f34, image);
+ break;
+ case GUEST_CODE_CONTAINER:
+ f34->v7.img.contains_guest_code = true;
+ f34->v7.img.guest_code.data = content;
+ f34->v7.img.guest_code.size = length;
+ break;
+ case DISPLAY_CONFIG_CONTAINER:
+ f34->v7.img.contains_display_cfg = true;
+ f34->v7.img.dp_config.data = content;
+ f34->v7.img.dp_config.size = length;
+ break;
+ case FLASH_CONFIG_CONTAINER:
+ f34->v7.img.contains_flash_config = true;
+ f34->v7.img.fl_config.data = content;
+ f34->v7.img.fl_config.size = length;
+ break;
+ case GENERAL_INFORMATION_CONTAINER:
+ f34->v7.img.contains_firmware_id = true;
+ f34->v7.img.firmware_id =
+ get_unaligned_le32(content + 4);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static int rmi_f34v7_parse_image_info(struct f34_data *f34)
+{
+ const struct image_header_10 *header = f34->v7.image;
+
+ memset(&f34->v7.img, 0x00, sizeof(f34->v7.img));
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: header->major_header_version = %d\n",
+ __func__, header->major_header_version);
+
+ switch (header->major_header_version) {
+ case IMAGE_HEADER_VERSION_10:
+ rmi_f34v7_parse_image_header_10(f34);
+ break;
+ default:
+ dev_err(&f34->fn->dev, "Unsupported image file format %02X\n",
+ header->major_header_version);
+ return -EINVAL;
+ }
+
+ if (!f34->v7.img.contains_flash_config) {
+ dev_err(&f34->fn->dev, "%s: No flash config in fw image\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ rmi_f34v7_parse_partition_table(f34, f34->v7.img.fl_config.data,
+ &f34->v7.img.blkcount, &f34->v7.img.phyaddr);
+
+ rmi_f34v7_compare_partition_tables(f34);
+
+ return 0;
+}
+
+int rmi_f34v7_do_reflash(struct f34_data *f34, const struct firmware *fw)
+{
+ int ret;
+
+ rmi_f34v7_read_queries_bl_version(f34);
+
+ f34->v7.image = fw->data;
+
+ ret = rmi_f34v7_parse_image_info(f34);
+ if (ret < 0)
+ goto fail;
+
+ if (!f34->v7.new_partition_table) {
+ ret = rmi_f34v7_check_ui_firmware_size(f34);
+ if (ret < 0)
+ goto fail;
+
+ ret = rmi_f34v7_check_ui_config_size(f34);
+ if (ret < 0)
+ goto fail;
+
+ if (f34->v7.has_display_cfg &&
+ f34->v7.img.contains_display_cfg) {
+ ret = rmi_f34v7_check_dp_config_size(f34);
+ if (ret < 0)
+ goto fail;
+ }
+
+ if (f34->v7.has_guest_code && f34->v7.img.contains_guest_code) {
+ ret = rmi_f34v7_check_guest_code_size(f34);
+ if (ret < 0)
+ goto fail;
+ }
+ } else {
+ ret = rmi_f34v7_check_bl_config_size(f34);
+ if (ret < 0)
+ goto fail;
+ }
+
+ ret = rmi_f34v7_erase_all(f34);
+ if (ret < 0)
+ goto fail;
+
+ if (f34->v7.new_partition_table) {
+ ret = rmi_f34v7_write_partition_table(f34);
+ if (ret < 0)
+ goto fail;
+ dev_info(&f34->fn->dev, "%s: Partition table programmed\n",
+ __func__);
+ }
+
+ dev_info(&f34->fn->dev, "Writing firmware (%d bytes)...\n",
+ f34->v7.img.ui_firmware.size);
+
+ ret = rmi_f34v7_write_firmware(f34);
+ if (ret < 0)
+ goto fail;
+
+ dev_info(&f34->fn->dev, "Writing config (%d bytes)...\n",
+ f34->v7.img.ui_config.size);
+
+ f34->v7.config_area = v7_UI_CONFIG_AREA;
+ ret = rmi_f34v7_write_ui_config(f34);
+ if (ret < 0)
+ goto fail;
+
+ if (f34->v7.has_display_cfg && f34->v7.img.contains_display_cfg) {
+ dev_info(&f34->fn->dev, "Writing display config...\n");
+
+ ret = rmi_f34v7_write_dp_config(f34);
+ if (ret < 0)
+ goto fail;
+ }
+
+ if (f34->v7.new_partition_table) {
+ if (f34->v7.has_guest_code && f34->v7.img.contains_guest_code) {
+ dev_info(&f34->fn->dev, "Writing guest code...\n");
+
+ ret = rmi_f34v7_write_guest_code(f34);
+ if (ret < 0)
+ goto fail;
+ }
+ }
+
+fail:
+ return ret;
+}
+
+static int rmi_f34v7_enter_flash_prog(struct f34_data *f34)
+{
+ int ret;
+
+ ret = rmi_f34v7_read_flash_status(f34);
+ if (ret < 0)
+ return ret;
+
+ if (f34->v7.in_bl_mode)
+ return 0;
+
+ ret = rmi_f34v7_write_command(f34, v7_CMD_ENABLE_FLASH_PROG);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+ if (ret < 0)
+ return ret;
+
+ if (!f34->v7.in_bl_mode) {
+ dev_err(&f34->fn->dev, "%s: BL mode not entered\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int rmi_f34v7_start_reflash(struct f34_data *f34, const struct firmware *fw)
+{
+ int ret = 0;
+
+ f34->v7.config_area = v7_UI_CONFIG_AREA;
+ f34->v7.image = fw->data;
+
+ ret = rmi_f34v7_parse_image_info(f34);
+ if (ret < 0)
+ goto exit;
+
+ if (!f34->v7.force_update && f34->v7.new_partition_table) {
+ dev_err(&f34->fn->dev, "%s: Partition table mismatch\n",
+ __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ dev_info(&f34->fn->dev, "Firmware image OK\n");
+
+ ret = rmi_f34v7_read_flash_status(f34);
+ if (ret < 0)
+ goto exit;
+
+ if (f34->v7.in_bl_mode) {
+ dev_info(&f34->fn->dev, "%s: Device in bootloader mode\n",
+ __func__);
+ }
+
+ rmi_f34v7_enter_flash_prog(f34);
+
+ return 0;
+
+exit:
+ return ret;
+}
+
+int rmi_f34v7_probe(struct f34_data *f34)
+{
+ int ret;
+
+ /* Read bootloader version */
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ f34->fn->fd.query_base_addr + V7_BOOTLOADER_ID_OFFSET,
+ f34->bootloader_id,
+ sizeof(f34->bootloader_id));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to read bootloader ID\n",
+ __func__);
+ return ret;
+ }
+
+ if (f34->bootloader_id[1] == '5') {
+ f34->bl_version = 5;
+ } else if (f34->bootloader_id[1] == '6') {
+ f34->bl_version = 6;
+ } else if (f34->bootloader_id[1] == 7) {
+ f34->bl_version = 7;
+ } else {
+ dev_err(&f34->fn->dev, "%s: Unrecognized bootloader version\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ memset(&f34->v7.blkcount, 0x00, sizeof(f34->v7.blkcount));
+ memset(&f34->v7.phyaddr, 0x00, sizeof(f34->v7.phyaddr));
+ rmi_f34v7_read_queries(f34);
+
+ f34->v7.force_update = false;
+ return 0;
+}
diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c
index cf805b960866..dea63e2db3e6 100644
--- a/drivers/input/rmi4/rmi_f54.c
+++ b/drivers/input/rmi4/rmi_f54.c
@@ -200,7 +200,7 @@ static int rmi_f54_request_report(struct rmi_function *fn, u8 report_type)
error = rmi_write(rmi_dev, fn->fd.command_base_addr, F54_GET_REPORT);
if (error < 0)
- return error;
+ goto unlock;
init_completion(&f54->cmd_done);
@@ -209,15 +209,18 @@ static int rmi_f54_request_report(struct rmi_function *fn, u8 report_type)
queue_delayed_work(f54->workqueue, &f54->work, 0);
+unlock:
mutex_unlock(&f54->data_mutex);
- return 0;
+ return error;
}
static size_t rmi_f54_get_report_size(struct f54_data *f54)
{
- u8 rx = f54->num_rx_electrodes ? : f54->num_rx_electrodes;
- u8 tx = f54->num_tx_electrodes ? : f54->num_tx_electrodes;
+ struct rmi_device *rmi_dev = f54->fn->rmi_dev;
+ struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
+ u8 rx = drv_data->num_rx_electrodes ? : f54->num_rx_electrodes;
+ u8 tx = drv_data->num_tx_electrodes ? : f54->num_tx_electrodes;
size_t size;
switch (rmi_f54_get_reptype(f54, f54->input)) {
@@ -401,6 +404,10 @@ static int rmi_f54_vidioc_enum_input(struct file *file, void *priv,
static int rmi_f54_set_input(struct f54_data *f54, unsigned int i)
{
+ struct rmi_device *rmi_dev = f54->fn->rmi_dev;
+ struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
+ u8 rx = drv_data->num_rx_electrodes ? : f54->num_rx_electrodes;
+ u8 tx = drv_data->num_tx_electrodes ? : f54->num_tx_electrodes;
struct v4l2_pix_format *f = &f54->format;
enum rmi_f54_report_type reptype;
int ret;
@@ -415,8 +422,8 @@ static int rmi_f54_set_input(struct f54_data *f54, unsigned int i)
f54->input = i;
- f->width = f54->num_rx_electrodes;
- f->height = f54->num_tx_electrodes;
+ f->width = rx;
+ f->height = tx;
f->field = V4L2_FIELD_NONE;
f->colorspace = V4L2_COLORSPACE_RAW;
f->bytesperline = f->width * sizeof(u16);
diff --git a/drivers/input/rmi4/rmi_f55.c b/drivers/input/rmi4/rmi_f55.c
new file mode 100644
index 000000000000..37390ca6a924
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f55.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2012-2015 Synaptics Incorporated
+ * Copyright (C) 2016 Zodiac Inflight Innovations
+ *
+ * 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.
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/slab.h>
+#include "rmi_driver.h"
+
+#define F55_NAME "rmi4_f55"
+
+/* F55 data offsets */
+#define F55_NUM_RX_OFFSET 0
+#define F55_NUM_TX_OFFSET 1
+#define F55_PHYS_CHAR_OFFSET 2
+
+/* Only read required query registers */
+#define F55_QUERY_LEN 3
+
+/* F55 capabilities */
+#define F55_CAP_SENSOR_ASSIGN BIT(0)
+
+struct f55_data {
+ struct rmi_function *fn;
+
+ u8 qry[F55_QUERY_LEN];
+ u8 num_rx_electrodes;
+ u8 cfg_num_rx_electrodes;
+ u8 num_tx_electrodes;
+ u8 cfg_num_tx_electrodes;
+};
+
+static int rmi_f55_detect(struct rmi_function *fn)
+{
+ struct rmi_device *rmi_dev = fn->rmi_dev;
+ struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
+ struct f55_data *f55;
+ int error;
+
+ f55 = dev_get_drvdata(&fn->dev);
+
+ error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
+ &f55->qry, sizeof(f55->qry));
+ if (error) {
+ dev_err(&fn->dev, "%s: Failed to query F55 properties\n",
+ __func__);
+ return error;
+ }
+
+ f55->num_rx_electrodes = f55->qry[F55_NUM_RX_OFFSET];
+ f55->num_tx_electrodes = f55->qry[F55_NUM_TX_OFFSET];
+
+ f55->cfg_num_rx_electrodes = f55->num_rx_electrodes;
+ f55->cfg_num_tx_electrodes = f55->num_rx_electrodes;
+
+ drv_data->num_rx_electrodes = f55->cfg_num_rx_electrodes;
+ drv_data->num_tx_electrodes = f55->cfg_num_rx_electrodes;
+
+ if (f55->qry[F55_PHYS_CHAR_OFFSET] & F55_CAP_SENSOR_ASSIGN) {
+ int i, total;
+ u8 buf[256];
+
+ /*
+ * Calculate the number of enabled receive and transmit
+ * electrodes by reading F55:Ctrl1 (sensor receiver assignment)
+ * and F55:Ctrl2 (sensor transmitter assignment). The number of
+ * enabled electrodes is the sum of all field entries with a
+ * value other than 0xff.
+ */
+ error = rmi_read_block(fn->rmi_dev,
+ fn->fd.control_base_addr + 1,
+ buf, f55->num_rx_electrodes);
+ if (!error) {
+ total = 0;
+ for (i = 0; i < f55->num_rx_electrodes; i++) {
+ if (buf[i] != 0xff)
+ total++;
+ }
+ f55->cfg_num_rx_electrodes = total;
+ drv_data->num_rx_electrodes = total;
+ }
+
+ error = rmi_read_block(fn->rmi_dev,
+ fn->fd.control_base_addr + 2,
+ buf, f55->num_tx_electrodes);
+ if (!error) {
+ total = 0;
+ for (i = 0; i < f55->num_tx_electrodes; i++) {
+ if (buf[i] != 0xff)
+ total++;
+ }
+ f55->cfg_num_tx_electrodes = total;
+ drv_data->num_tx_electrodes = total;
+ }
+ }
+
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_rx_electrodes: %d (raw %d)\n",
+ f55->cfg_num_rx_electrodes, f55->num_rx_electrodes);
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_tx_electrodes: %d (raw %d)\n",
+ f55->cfg_num_tx_electrodes, f55->num_tx_electrodes);
+
+ return 0;
+}
+
+static int rmi_f55_probe(struct rmi_function *fn)
+{
+ struct f55_data *f55;
+
+ f55 = devm_kzalloc(&fn->dev, sizeof(struct f55_data), GFP_KERNEL);
+ if (!f55)
+ return -ENOMEM;
+
+ f55->fn = fn;
+ dev_set_drvdata(&fn->dev, f55);
+
+ return rmi_f55_detect(fn);
+}
+
+struct rmi_function_handler rmi_f55_handler = {
+ .driver = {
+ .name = F55_NAME,
+ },
+ .func = 0x55,
+ .probe = rmi_f55_probe,
+};
diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c
index 1ebc2c1debae..082306d7c207 100644
--- a/drivers/input/rmi4/rmi_i2c.c
+++ b/drivers/input/rmi4/rmi_i2c.c
@@ -9,7 +9,6 @@
#include <linux/i2c.h>
#include <linux/rmi.h>
-#include <linux/irq.h>
#include <linux/of.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
@@ -35,8 +34,6 @@ struct rmi_i2c_xport {
struct mutex page_mutex;
int page;
- int irq;
-
u8 *tx_buf;
size_t tx_buf_size;
@@ -177,42 +174,6 @@ static const struct rmi_transport_ops rmi_i2c_ops = {
.read_block = rmi_i2c_read_block,
};
-static irqreturn_t rmi_i2c_irq(int irq, void *dev_id)
-{
- struct rmi_i2c_xport *rmi_i2c = dev_id;
- struct rmi_device *rmi_dev = rmi_i2c->xport.rmi_dev;
- int ret;
-
- ret = rmi_process_interrupt_requests(rmi_dev);
- if (ret)
- rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev,
- "Failed to process interrupt request: %d\n", ret);
-
- return IRQ_HANDLED;
-}
-
-static int rmi_i2c_init_irq(struct i2c_client *client)
-{
- struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
- int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_i2c->irq));
- int ret;
-
- if (!irq_flags)
- irq_flags = IRQF_TRIGGER_LOW;
-
- ret = devm_request_threaded_irq(&client->dev, rmi_i2c->irq, NULL,
- rmi_i2c_irq, irq_flags | IRQF_ONESHOT, client->name,
- rmi_i2c);
- if (ret < 0) {
- dev_warn(&client->dev, "Failed to register interrupt %d\n",
- rmi_i2c->irq);
-
- return ret;
- }
-
- return 0;
-}
-
#ifdef CONFIG_OF
static const struct of_device_id rmi_i2c_of_match[] = {
{ .compatible = "syna,rmi4-i2c" },
@@ -255,8 +216,7 @@ static int rmi_i2c_probe(struct i2c_client *client,
if (!client->dev.of_node && client_pdata)
*pdata = *client_pdata;
- if (client->irq > 0)
- rmi_i2c->irq = client->irq;
+ pdata->irq = client->irq;
rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n",
dev_name(&client->dev));
@@ -321,10 +281,6 @@ static int rmi_i2c_probe(struct i2c_client *client,
if (retval)
return retval;
- retval = rmi_i2c_init_irq(client);
- if (retval < 0)
- return retval;
-
dev_info(&client->dev, "registered rmi i2c driver at %#04x.\n",
client->addr);
return 0;
@@ -337,18 +293,10 @@ static int rmi_i2c_suspend(struct device *dev)
struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
int ret;
- ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev);
+ ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, true);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
- disable_irq(rmi_i2c->irq);
- if (device_may_wakeup(&client->dev)) {
- ret = enable_irq_wake(rmi_i2c->irq);
- if (!ret)
- dev_warn(dev, "Failed to enable irq for wake: %d\n",
- ret);
- }
-
regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
rmi_i2c->supplies);
@@ -368,15 +316,7 @@ static int rmi_i2c_resume(struct device *dev)
msleep(rmi_i2c->startup_delay);
- enable_irq(rmi_i2c->irq);
- if (device_may_wakeup(&client->dev)) {
- ret = disable_irq_wake(rmi_i2c->irq);
- if (!ret)
- dev_warn(dev, "Failed to disable irq for wake: %d\n",
- ret);
- }
-
- ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev);
+ ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, true);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
@@ -391,12 +331,10 @@ static int rmi_i2c_runtime_suspend(struct device *dev)
struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
int ret;
- ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev);
+ ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, false);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
- disable_irq(rmi_i2c->irq);
-
regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
rmi_i2c->supplies);
@@ -416,9 +354,7 @@ static int rmi_i2c_runtime_resume(struct device *dev)
msleep(rmi_i2c->startup_delay);
- enable_irq(rmi_i2c->irq);
-
- ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev);
+ ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, false);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c
new file mode 100644
index 000000000000..76752555d809
--- /dev/null
+++ b/drivers/input/rmi4/rmi_smbus.c
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2015 - 2016 Red Hat, Inc
+ * Copyright (c) 2011, 2012 Synaptics Incorporated
+ * Copyright (c) 2011 Unixphere
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kconfig.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/rmi.h>
+#include <linux/slab.h>
+#include "rmi_driver.h"
+
+#define SMB_PROTOCOL_VERSION_ADDRESS 0xfd
+#define SMB_MAX_COUNT 32
+#define RMI_SMB2_MAP_SIZE 8 /* 8 entry of 4 bytes each */
+#define RMI_SMB2_MAP_FLAGS_WE 0x01
+
+struct mapping_table_entry {
+ __le16 rmiaddr;
+ u8 readcount;
+ u8 flags;
+};
+
+struct rmi_smb_xport {
+ struct rmi_transport_dev xport;
+ struct i2c_client *client;
+
+ struct mutex page_mutex;
+ int page;
+ u8 table_index;
+ struct mutex mappingtable_mutex;
+ struct mapping_table_entry mapping_table[RMI_SMB2_MAP_SIZE];
+};
+
+static int rmi_smb_get_version(struct rmi_smb_xport *rmi_smb)
+{
+ struct i2c_client *client = rmi_smb->client;
+ int retval;
+
+ /* Check if for SMBus new version device by reading version byte. */
+ retval = i2c_smbus_read_byte_data(client, SMB_PROTOCOL_VERSION_ADDRESS);
+ if (retval < 0) {
+ dev_err(&client->dev, "failed to get SMBus version number!\n");
+ return retval;
+ }
+ return retval + 1;
+}
+
+/* SMB block write - wrapper over ic2_smb_write_block */
+static int smb_block_write(struct rmi_transport_dev *xport,
+ u8 commandcode, const void *buf, size_t len)
+{
+ struct rmi_smb_xport *rmi_smb =
+ container_of(xport, struct rmi_smb_xport, xport);
+ struct i2c_client *client = rmi_smb->client;
+ int retval;
+
+ retval = i2c_smbus_write_block_data(client, commandcode, len, buf);
+
+ rmi_dbg(RMI_DEBUG_XPORT, &client->dev,
+ "wrote %zd bytes at %#04x: %d (%*ph)\n",
+ len, commandcode, retval, (int)len, buf);
+
+ return retval;
+}
+
+/*
+ * The function to get command code for smbus operations and keeps
+ * records to the driver mapping table
+ */
+static int rmi_smb_get_command_code(struct rmi_transport_dev *xport,
+ u16 rmiaddr, int bytecount, bool isread, u8 *commandcode)
+{
+ struct rmi_smb_xport *rmi_smb =
+ container_of(xport, struct rmi_smb_xport, xport);
+ int i;
+ int retval;
+ struct mapping_table_entry mapping_data[1];
+
+ mutex_lock(&rmi_smb->mappingtable_mutex);
+ for (i = 0; i < RMI_SMB2_MAP_SIZE; i++) {
+ if (rmi_smb->mapping_table[i].rmiaddr == rmiaddr) {
+ if (isread) {
+ if (rmi_smb->mapping_table[i].readcount
+ == bytecount) {
+ *commandcode = i;
+ retval = 0;
+ goto exit;
+ }
+ } else {
+ if (rmi_smb->mapping_table[i].flags &
+ RMI_SMB2_MAP_FLAGS_WE) {
+ *commandcode = i;
+ retval = 0;
+ goto exit;
+ }
+ }
+ }
+ }
+ i = rmi_smb->table_index;
+ rmi_smb->table_index = (i + 1) % RMI_SMB2_MAP_SIZE;
+
+ /* constructs mapping table data entry. 4 bytes each entry */
+ memset(mapping_data, 0, sizeof(mapping_data));
+
+ mapping_data[0].rmiaddr = cpu_to_le16(rmiaddr);
+ mapping_data[0].readcount = bytecount;
+ mapping_data[0].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0;
+
+ retval = smb_block_write(xport, i + 0x80, mapping_data,
+ sizeof(mapping_data));
+
+ if (retval < 0) {
+ /*
+ * if not written to device mapping table
+ * clear the driver mapping table records
+ */
+ rmi_smb->mapping_table[i].rmiaddr = 0x0000;
+ rmi_smb->mapping_table[i].readcount = 0;
+ rmi_smb->mapping_table[i].flags = 0;
+ goto exit;
+ }
+ /* save to the driver level mapping table */
+ rmi_smb->mapping_table[i].rmiaddr = rmiaddr;
+ rmi_smb->mapping_table[i].readcount = bytecount;
+ rmi_smb->mapping_table[i].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0;
+ *commandcode = i;
+
+exit:
+ mutex_unlock(&rmi_smb->mappingtable_mutex);
+
+ return retval;
+}
+
+static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr,
+ const void *databuff, size_t len)
+{
+ int retval = 0;
+ u8 commandcode;
+ struct rmi_smb_xport *rmi_smb =
+ container_of(xport, struct rmi_smb_xport, xport);
+ int cur_len = (int)len;
+
+ mutex_lock(&rmi_smb->page_mutex);
+
+ while (cur_len > 0) {
+ /*
+ * break into 32 bytes chunks to write get command code
+ */
+ int block_len = min_t(int, len, SMB_MAX_COUNT);
+
+ retval = rmi_smb_get_command_code(xport, rmiaddr, block_len,
+ false, &commandcode);
+ if (retval < 0)
+ goto exit;
+
+ retval = smb_block_write(xport, commandcode,
+ databuff, block_len);
+ if (retval < 0)
+ goto exit;
+
+ /* prepare to write next block of bytes */
+ cur_len -= SMB_MAX_COUNT;
+ databuff += SMB_MAX_COUNT;
+ rmiaddr += SMB_MAX_COUNT;
+ }
+exit:
+ mutex_unlock(&rmi_smb->page_mutex);
+ return retval;
+}
+
+/* SMB block read - wrapper over ic2_smb_read_block */
+static int smb_block_read(struct rmi_transport_dev *xport,
+ u8 commandcode, void *buf, size_t len)
+{
+ struct rmi_smb_xport *rmi_smb =
+ container_of(xport, struct rmi_smb_xport, xport);
+ struct i2c_client *client = rmi_smb->client;
+ int retval;
+
+ retval = i2c_smbus_read_block_data(client, commandcode, buf);
+ if (retval < 0)
+ return retval;
+
+ return retval;
+}
+
+static int rmi_smb_read_block(struct rmi_transport_dev *xport, u16 rmiaddr,
+ void *databuff, size_t len)
+{
+ struct rmi_smb_xport *rmi_smb =
+ container_of(xport, struct rmi_smb_xport, xport);
+ int retval;
+ u8 commandcode;
+ int cur_len = (int)len;
+
+ mutex_lock(&rmi_smb->page_mutex);
+ memset(databuff, 0, len);
+
+ while (cur_len > 0) {
+ /* break into 32 bytes chunks to write get command code */
+ int block_len = min_t(int, cur_len, SMB_MAX_COUNT);
+
+ retval = rmi_smb_get_command_code(xport, rmiaddr, block_len,
+ true, &commandcode);
+ if (retval < 0)
+ goto exit;
+
+ retval = smb_block_read(xport, commandcode,
+ databuff, block_len);
+ if (retval < 0)
+ goto exit;
+
+ /* prepare to read next block of bytes */
+ cur_len -= SMB_MAX_COUNT;
+ databuff += SMB_MAX_COUNT;
+ rmiaddr += SMB_MAX_COUNT;
+ }
+
+ retval = 0;
+
+exit:
+ mutex_unlock(&rmi_smb->page_mutex);
+ return retval;
+}
+
+static void rmi_smb_clear_state(struct rmi_smb_xport *rmi_smb)
+{
+ /* the mapping table has been flushed, discard the current one */
+ mutex_lock(&rmi_smb->mappingtable_mutex);
+ memset(rmi_smb->mapping_table, 0, sizeof(rmi_smb->mapping_table));
+ mutex_unlock(&rmi_smb->mappingtable_mutex);
+}
+
+static int rmi_smb_enable_smbus_mode(struct rmi_smb_xport *rmi_smb)
+{
+ int retval;
+
+ /* we need to get the smbus version to activate the touchpad */
+ retval = rmi_smb_get_version(rmi_smb);
+ if (retval < 0)
+ return retval;
+
+ return 0;
+}
+
+static int rmi_smb_reset(struct rmi_transport_dev *xport, u16 reset_addr)
+{
+ struct rmi_smb_xport *rmi_smb =
+ container_of(xport, struct rmi_smb_xport, xport);
+
+ rmi_smb_clear_state(rmi_smb);
+
+ /*
+ * we do not call the actual reset command, it has to be handled in
+ * PS/2 or there will be races between PS/2 and SMBus.
+ * PS/2 should ensure that a psmouse_reset is called before
+ * intializing the device and after it has been removed to be in a known
+ * state.
+ */
+ return rmi_smb_enable_smbus_mode(rmi_smb);
+}
+
+static const struct rmi_transport_ops rmi_smb_ops = {
+ .write_block = rmi_smb_write_block,
+ .read_block = rmi_smb_read_block,
+ .reset = rmi_smb_reset,
+};
+
+static int rmi_smb_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct rmi_device_platform_data *pdata = dev_get_platdata(&client->dev);
+ struct rmi_smb_xport *rmi_smb;
+ int retval;
+ int smbus_version;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+ I2C_FUNC_SMBUS_HOST_NOTIFY)) {
+ dev_err(&client->dev,
+ "adapter does not support required functionality.\n");
+ return -ENODEV;
+ }
+
+ if (client->irq <= 0) {
+ dev_err(&client->dev, "no IRQ provided, giving up.\n");
+ return client->irq ? client->irq : -ENODEV;
+ }
+
+ rmi_smb = devm_kzalloc(&client->dev, sizeof(struct rmi_smb_xport),
+ GFP_KERNEL);
+ if (!rmi_smb)
+ return -ENOMEM;
+
+ if (!pdata) {
+ dev_err(&client->dev, "no platform data, aborting\n");
+ return -ENOMEM;
+ }
+
+ rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n",
+ dev_name(&client->dev));
+
+ rmi_smb->client = client;
+ mutex_init(&rmi_smb->page_mutex);
+ mutex_init(&rmi_smb->mappingtable_mutex);
+
+ rmi_smb->xport.dev = &client->dev;
+ rmi_smb->xport.pdata = *pdata;
+ rmi_smb->xport.pdata.irq = client->irq;
+ rmi_smb->xport.proto_name = "smb2";
+ rmi_smb->xport.ops = &rmi_smb_ops;
+
+ retval = rmi_smb_get_version(rmi_smb);
+ if (retval < 0)
+ return retval;
+
+ smbus_version = retval;
+ rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Smbus version is %d",
+ smbus_version);
+
+ if (smbus_version != 2) {
+ dev_err(&client->dev, "Unrecognized SMB version %d.\n",
+ smbus_version);
+ return -ENODEV;
+ }
+
+ i2c_set_clientdata(client, rmi_smb);
+
+ retval = rmi_register_transport_device(&rmi_smb->xport);
+ if (retval) {
+ dev_err(&client->dev, "Failed to register transport driver at 0x%.2X.\n",
+ client->addr);
+ i2c_set_clientdata(client, NULL);
+ return retval;
+ }
+
+ dev_info(&client->dev, "registered rmi smb driver at %#04x.\n",
+ client->addr);
+ return 0;
+
+}
+
+static int rmi_smb_remove(struct i2c_client *client)
+{
+ struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+
+ rmi_unregister_transport_device(&rmi_smb->xport);
+
+ return 0;
+}
+
+static int __maybe_unused rmi_smb_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+ int ret;
+
+ ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, true);
+ if (ret)
+ dev_warn(dev, "Failed to suspend device: %d\n", ret);
+
+ return ret;
+}
+
+static int __maybe_unused rmi_smb_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+ int ret;
+
+ ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, false);
+ if (ret)
+ dev_warn(dev, "Failed to suspend device: %d\n", ret);
+
+ return ret;
+}
+
+static int __maybe_unused rmi_smb_resume(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+ struct rmi_device *rmi_dev = rmi_smb->xport.rmi_dev;
+ int ret;
+
+ rmi_smb_reset(&rmi_smb->xport, 0);
+
+ rmi_reset(rmi_dev);
+
+ ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, true);
+ if (ret)
+ dev_warn(dev, "Failed to resume device: %d\n", ret);
+
+ return 0;
+}
+
+static int __maybe_unused rmi_smb_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+ int ret;
+
+ ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, false);
+ if (ret)
+ dev_warn(dev, "Failed to resume device: %d\n", ret);
+
+ return 0;
+}
+
+static const struct dev_pm_ops rmi_smb_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(rmi_smb_suspend, rmi_smb_resume)
+ SET_RUNTIME_PM_OPS(rmi_smb_runtime_suspend, rmi_smb_runtime_resume,
+ NULL)
+};
+
+static const struct i2c_device_id rmi_id[] = {
+ { "rmi4_smbus", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rmi_id);
+
+static struct i2c_driver rmi_smb_driver = {
+ .driver = {
+ .name = "rmi4_smbus",
+ .pm = &rmi_smb_pm,
+ },
+ .id_table = rmi_id,
+ .probe = rmi_smb_probe,
+ .remove = rmi_smb_remove,
+};
+
+module_i2c_driver(rmi_smb_driver);
+
+MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>");
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
+MODULE_DESCRIPTION("RMI4 SMBus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/rmi4/rmi_spi.c b/drivers/input/rmi4/rmi_spi.c
index 4ebef607e214..69548d7d1f10 100644
--- a/drivers/input/rmi4/rmi_spi.c
+++ b/drivers/input/rmi4/rmi_spi.c
@@ -12,7 +12,6 @@
#include <linux/rmi.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
-#include <linux/irq.h>
#include <linux/of.h>
#include "rmi_driver.h"
@@ -44,8 +43,6 @@ struct rmi_spi_xport {
struct mutex page_mutex;
int page;
- int irq;
-
u8 *rx_buf;
u8 *tx_buf;
int xfer_buf_size;
@@ -326,41 +323,6 @@ static const struct rmi_transport_ops rmi_spi_ops = {
.read_block = rmi_spi_read_block,
};
-static irqreturn_t rmi_spi_irq(int irq, void *dev_id)
-{
- struct rmi_spi_xport *rmi_spi = dev_id;
- struct rmi_device *rmi_dev = rmi_spi->xport.rmi_dev;
- int ret;
-
- ret = rmi_process_interrupt_requests(rmi_dev);
- if (ret)
- rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev,
- "Failed to process interrupt request: %d\n", ret);
-
- return IRQ_HANDLED;
-}
-
-static int rmi_spi_init_irq(struct spi_device *spi)
-{
- struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
- int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_spi->irq));
- int ret;
-
- if (!irq_flags)
- irq_flags = IRQF_TRIGGER_LOW;
-
- ret = devm_request_threaded_irq(&spi->dev, rmi_spi->irq, NULL,
- rmi_spi_irq, irq_flags | IRQF_ONESHOT,
- dev_name(&spi->dev), rmi_spi);
- if (ret < 0) {
- dev_warn(&spi->dev, "Failed to register interrupt %d\n",
- rmi_spi->irq);
- return ret;
- }
-
- return 0;
-}
-
#ifdef CONFIG_OF
static int rmi_spi_of_probe(struct spi_device *spi,
struct rmi_device_platform_data *pdata)
@@ -440,8 +402,7 @@ static int rmi_spi_probe(struct spi_device *spi)
return retval;
}
- if (spi->irq > 0)
- rmi_spi->irq = spi->irq;
+ pdata->irq = spi->irq;
rmi_spi->spi = spi;
mutex_init(&rmi_spi->page_mutex);
@@ -477,10 +438,6 @@ static int rmi_spi_probe(struct spi_device *spi)
if (retval)
return retval;
- retval = rmi_spi_init_irq(spi);
- if (retval < 0)
- return retval;
-
dev_info(&spi->dev, "registered RMI SPI driver\n");
return 0;
}
@@ -492,17 +449,10 @@ static int rmi_spi_suspend(struct device *dev)
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
int ret;
- ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev);
+ ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, true);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
- disable_irq(rmi_spi->irq);
- if (device_may_wakeup(&spi->dev)) {
- ret = enable_irq_wake(rmi_spi->irq);
- if (!ret)
- dev_warn(dev, "Failed to enable irq for wake: %d\n",
- ret);
- }
return ret;
}
@@ -512,15 +462,7 @@ static int rmi_spi_resume(struct device *dev)
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
int ret;
- enable_irq(rmi_spi->irq);
- if (device_may_wakeup(&spi->dev)) {
- ret = disable_irq_wake(rmi_spi->irq);
- if (!ret)
- dev_warn(dev, "Failed to disable irq for wake: %d\n",
- ret);
- }
-
- ret = rmi_driver_resume(rmi_spi->xport.rmi_dev);
+ ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, true);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
@@ -535,12 +477,10 @@ static int rmi_spi_runtime_suspend(struct device *dev)
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
int ret;
- ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev);
+ ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, false);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
- disable_irq(rmi_spi->irq);
-
return 0;
}
@@ -550,9 +490,7 @@ static int rmi_spi_runtime_resume(struct device *dev)
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
int ret;
- enable_irq(rmi_spi->irq);
-
- ret = rmi_driver_resume(rmi_spi->xport.rmi_dev);
+ ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, false);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 073246c7d163..73a4e68448fc 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -517,79 +517,7 @@ static const struct dmi_system_id i8042_dmi_noselftest_table[] = {
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "A455LD"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "K401LB"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "K501LB"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "K501LX"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "R409L"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "V502LX"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "X302LA"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "X450LD"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "X455LAB"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "X455LDB"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "X455LF"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "Z450LA"),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
},
},
{ }
@@ -1131,10 +1059,10 @@ static int __init i8042_pnp_init(void)
return 0;
}
-#else
+#else /* !CONFIG_PNP */
static inline int i8042_pnp_init(void) { return 0; }
static inline void i8042_pnp_exit(void) { }
-#endif
+#endif /* CONFIG_PNP */
static int __init i8042_platform_init(void)
{
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 89abfdb539ac..62685a768913 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -387,7 +387,7 @@ static int i8042_aux_write(struct serio *serio, unsigned char c)
/*
- * i8042_aux_close attempts to clear AUX or KBD port state by disabling
+ * i8042_port_close attempts to clear AUX or KBD port state by disabling
* and then re-enabling it.
*/
diff --git a/drivers/input/touchscreen/fsl-imx25-tcq.c b/drivers/input/touchscreen/fsl-imx25-tcq.c
index fe9877a6af9e..d50ee490c9cc 100644
--- a/drivers/input/touchscreen/fsl-imx25-tcq.c
+++ b/drivers/input/touchscreen/fsl-imx25-tcq.c
@@ -55,6 +55,7 @@ static const struct of_device_id mx25_tcq_ids[] = {
{ .compatible = "fsl,imx25-tcq", },
{ /* Sentinel */ }
};
+MODULE_DEVICE_TABLE(of, mx25_tcq_ids);
#define TSC_4WIRE_PRE_INDEX 0
#define TSC_4WIRE_X_INDEX 1
diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c
index 8275267eac25..7098e0a47019 100644
--- a/drivers/input/touchscreen/imx6ul_tsc.c
+++ b/drivers/input/touchscreen/imx6ul_tsc.c
@@ -21,17 +21,25 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/log2.h>
/* ADC configuration registers field define */
#define ADC_AIEN (0x1 << 7)
#define ADC_CONV_DISABLE 0x1F
+#define ADC_AVGE (0x1 << 5)
#define ADC_CAL (0x1 << 7)
#define ADC_CALF 0x2
#define ADC_12BIT_MODE (0x2 << 2)
+#define ADC_CONV_MODE_MASK (0x3 << 2)
#define ADC_IPG_CLK 0x00
+#define ADC_INPUT_CLK_MASK 0x3
#define ADC_CLK_DIV_8 (0x03 << 5)
+#define ADC_CLK_DIV_MASK (0x3 << 5)
#define ADC_SHORT_SAMPLE_MODE (0x0 << 4)
+#define ADC_SAMPLE_MODE_MASK (0x1 << 4)
#define ADC_HARDWARE_TRIGGER (0x1 << 13)
+#define ADC_AVGS_SHIFT 14
+#define ADC_AVGS_MASK (0x3 << 14)
#define SELECT_CHANNEL_4 0x04
#define SELECT_CHANNEL_1 0x01
#define DISABLE_CONVERSION_INT (0x0 << 7)
@@ -84,8 +92,10 @@ struct imx6ul_tsc {
struct clk *adc_clk;
struct gpio_desc *xnur_gpio;
- int measure_delay_time;
- int pre_charge_time;
+ u32 measure_delay_time;
+ u32 pre_charge_time;
+ bool average_enable;
+ u32 average_select;
struct completion completion;
};
@@ -96,17 +106,23 @@ struct imx6ul_tsc {
*/
static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
{
- int adc_hc = 0;
- int adc_gc;
- int adc_gs;
- int adc_cfg;
- int timeout;
+ u32 adc_hc = 0;
+ u32 adc_gc;
+ u32 adc_gs;
+ u32 adc_cfg;
+ unsigned long timeout;
reinit_completion(&tsc->completion);
adc_cfg = readl(tsc->adc_regs + REG_ADC_CFG);
+ adc_cfg &= ~(ADC_CONV_MODE_MASK | ADC_INPUT_CLK_MASK);
adc_cfg |= ADC_12BIT_MODE | ADC_IPG_CLK;
+ adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE_MASK);
adc_cfg |= ADC_CLK_DIV_8 | ADC_SHORT_SAMPLE_MODE;
+ if (tsc->average_enable) {
+ adc_cfg &= ~ADC_AVGS_MASK;
+ adc_cfg |= (tsc->average_select) << ADC_AVGS_SHIFT;
+ }
adc_cfg &= ~ADC_HARDWARE_TRIGGER;
writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG);
@@ -118,6 +134,8 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
/* start ADC calibration */
adc_gc = readl(tsc->adc_regs + REG_ADC_GC);
adc_gc |= ADC_CAL;
+ if (tsc->average_enable)
+ adc_gc |= ADC_AVGE;
writel(adc_gc, tsc->adc_regs + REG_ADC_GC);
timeout = wait_for_completion_timeout
@@ -148,7 +166,7 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
*/
static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc)
{
- int adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4;
+ u32 adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4;
adc_hc0 = DISABLE_CONVERSION_INT;
writel(adc_hc0, tsc->adc_regs + REG_ADC_HC0);
@@ -173,8 +191,8 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc)
*/
static void imx6ul_tsc_set(struct imx6ul_tsc *tsc)
{
- int basic_setting = 0;
- int start;
+ u32 basic_setting = 0;
+ u32 start;
basic_setting |= tsc->measure_delay_time << 8;
basic_setting |= DETECT_4_WIRE_MODE | AUTO_MEASURE;
@@ -209,8 +227,8 @@ static int imx6ul_tsc_init(struct imx6ul_tsc *tsc)
static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc)
{
- int tsc_flow;
- int adc_cfg;
+ u32 tsc_flow;
+ u32 adc_cfg;
/* TSC controller enters to idle status */
tsc_flow = readl(tsc->tsc_regs + REG_TSC_FLOW_CONTROL);
@@ -227,8 +245,8 @@ static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc)
static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc)
{
unsigned long timeout = jiffies + msecs_to_jiffies(2);
- int state_machine;
- int debug_mode2;
+ u32 state_machine;
+ u32 debug_mode2;
do {
if (time_after(jiffies, timeout))
@@ -246,10 +264,10 @@ static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc)
static irqreturn_t tsc_irq_fn(int irq, void *dev_id)
{
struct imx6ul_tsc *tsc = dev_id;
- int status;
- int value;
- int x, y;
- int start;
+ u32 status;
+ u32 value;
+ u32 x, y;
+ u32 start;
status = readl(tsc->tsc_regs + REG_TSC_INT_STATUS);
@@ -289,8 +307,8 @@ static irqreturn_t tsc_irq_fn(int irq, void *dev_id)
static irqreturn_t adc_irq_fn(int irq, void *dev_id)
{
struct imx6ul_tsc *tsc = dev_id;
- int coco;
- int value;
+ u32 coco;
+ u32 value;
coco = readl(tsc->adc_regs + REG_ADC_HS);
if (coco & 0x01) {
@@ -346,6 +364,7 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
int err;
int tsc_irq;
int adc_irq;
+ u32 average_samples;
tsc = devm_kzalloc(&pdev->dev, sizeof(*tsc), GFP_KERNEL);
if (!tsc)
@@ -450,6 +469,30 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
if (err)
tsc->pre_charge_time = 0xfff;
+ err = of_property_read_u32(np, "touchscreen-average-samples",
+ &average_samples);
+ if (err)
+ average_samples = 1;
+
+ switch (average_samples) {
+ case 1:
+ tsc->average_enable = false;
+ tsc->average_select = 0; /* value unused; initialize anyway */
+ break;
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ tsc->average_enable = true;
+ tsc->average_select = ilog2(average_samples) - 2;
+ break;
+ default:
+ dev_err(&pdev->dev,
+ "touchscreen-average-samples (%u) must be 1, 4, 8, 16 or 32\n",
+ average_samples);
+ return -EINVAL;
+ }
+
err = input_register_device(tsc->input);
if (err) {
dev_err(&pdev->dev,
diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c
index 552a3773f79d..703d7f983d0a 100644
--- a/drivers/input/touchscreen/melfas_mip4.c
+++ b/drivers/input/touchscreen/melfas_mip4.c
@@ -33,7 +33,7 @@
/*****************************************************************
* Protocol
- * Version : MIP 4.0 Rev 4.6
+ * Version : MIP 4.0 Rev 5.4
*****************************************************************/
/* Address */
@@ -81,6 +81,9 @@
#define MIP4_R1_INFO_IC_HW_CATEGORY 0x77
#define MIP4_R1_INFO_CONTACT_THD_SCR 0x78
#define MIP4_R1_INFO_CONTACT_THD_KEY 0x7A
+#define MIP4_R1_INFO_PID 0x7C
+#define MIP4_R1_INFO_VID 0x7E
+#define MIP4_R1_INFO_SLAVE_ADDR 0x80
#define MIP4_R0_EVENT 0x02
#define MIP4_R1_EVENT_SUPPORTED_FUNC 0x00
@@ -157,7 +160,9 @@ struct mip4_ts {
char phys[32];
char product_name[16];
+ u16 product_id;
char ic_name[4];
+ char fw_name[32];
unsigned int max_x;
unsigned int max_y;
@@ -264,6 +269,23 @@ static int mip4_query_device(struct mip4_ts *ts)
dev_dbg(&ts->client->dev, "product name: %.*s\n",
(int)sizeof(ts->product_name), ts->product_name);
+ /* Product ID */
+ cmd[0] = MIP4_R0_INFO;
+ cmd[1] = MIP4_R1_INFO_PID;
+ error = mip4_i2c_xfer(ts, cmd, sizeof(cmd), buf, 2);
+ if (error) {
+ dev_warn(&ts->client->dev,
+ "Failed to retrieve product id: %d\n", error);
+ } else {
+ ts->product_id = get_unaligned_le16(&buf[0]);
+ dev_dbg(&ts->client->dev, "product id: %04X\n", ts->product_id);
+ }
+
+ /* Firmware name */
+ snprintf(ts->fw_name, sizeof(ts->fw_name),
+ "melfas_mip4_%04X.fw", ts->product_id);
+ dev_dbg(&ts->client->dev, "firmware name: %s\n", ts->fw_name);
+
/* IC name */
cmd[0] = MIP4_R0_INFO;
cmd[1] = MIP4_R1_INFO_IC_NAME;
@@ -1269,11 +1291,11 @@ static ssize_t mip4_sysfs_fw_update(struct device *dev,
const struct firmware *fw;
int error;
- error = request_firmware(&fw, MIP4_FW_NAME, dev);
+ error = request_firmware(&fw, ts->fw_name, dev);
if (error) {
dev_err(&ts->client->dev,
"Failed to retrieve firmware %s: %d\n",
- MIP4_FW_NAME, error);
+ ts->fw_name, error);
return error;
}
@@ -1348,6 +1370,25 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev,
static DEVICE_ATTR(hw_version, S_IRUGO, mip4_sysfs_read_hw_version, NULL);
+static ssize_t mip4_sysfs_read_product_id(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mip4_ts *ts = i2c_get_clientdata(client);
+ size_t count;
+
+ mutex_lock(&ts->input->mutex);
+
+ count = snprintf(buf, PAGE_SIZE, "%04X\n", ts->product_id);
+
+ mutex_unlock(&ts->input->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(product_id, S_IRUGO, mip4_sysfs_read_product_id, NULL);
+
static ssize_t mip4_sysfs_read_ic_name(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -1371,6 +1412,7 @@ static DEVICE_ATTR(ic_name, S_IRUGO, mip4_sysfs_read_ic_name, NULL);
static struct attribute *mip4_attrs[] = {
&dev_attr_fw_version.attr,
&dev_attr_hw_version.attr,
+ &dev_attr_product_id.attr,
&dev_attr_ic_name.attr,
&dev_attr_update_fw.attr,
NULL,
@@ -1435,6 +1477,7 @@ static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id)
input->id.bustype = BUS_I2C;
input->id.vendor = 0x13c5;
+ input->id.product = ts->product_id;
input->open = mip4_input_open;
input->close = mip4_input_close;
@@ -1572,6 +1615,6 @@ static struct i2c_driver mip4_driver = {
module_i2c_driver(mip4_driver);
MODULE_DESCRIPTION("MELFAS MIP4 Touchscreen");
-MODULE_VERSION("2016.09.28");
+MODULE_VERSION("2016.10.31");
MODULE_AUTHOR("Sangwon Jee <jeesw@melfas.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c
index a99fb5cac5a0..2658afa016c9 100644
--- a/drivers/input/touchscreen/raydium_i2c_ts.c
+++ b/drivers/input/touchscreen/raydium_i2c_ts.c
@@ -669,7 +669,7 @@ static int raydium_i2c_do_update_firmware(struct raydium_data *ts,
if (ts->boot_mode == RAYDIUM_TS_MAIN) {
dev_err(&client->dev,
- "failied to jump to boot loader: %d\n",
+ "failed to jump to boot loader: %d\n",
error);
return -EIO;
}
diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index f502c8488be8..404830a4a366 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -29,6 +29,7 @@
#include <linux/input/touchscreen.h>
#include <linux/pm.h>
#include <linux/irq.h>
+#include <linux/regulator/consumer.h>
#include <asm/unaligned.h>
@@ -73,6 +74,7 @@ struct silead_ts_data {
struct i2c_client *client;
struct gpio_desc *gpio_power;
struct input_dev *input;
+ struct regulator_bulk_data regulators[2];
char fw_name[64];
struct touchscreen_properties prop;
u32 max_fingers;
@@ -433,6 +435,13 @@ static int silead_ts_set_default_fw_name(struct silead_ts_data *data,
}
#endif
+static void silead_disable_regulator(void *arg)
+{
+ struct silead_ts_data *data = arg;
+
+ regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
+}
+
static int silead_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -465,6 +474,26 @@ static int silead_ts_probe(struct i2c_client *client,
if (client->irq <= 0)
return -ENODEV;
+ data->regulators[0].supply = "vddio";
+ data->regulators[1].supply = "avdd";
+ error = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->regulators),
+ data->regulators);
+ if (error)
+ return error;
+
+ /*
+ * Enable regulators at probe and disable them at remove, we need
+ * to keep the chip powered otherwise it forgets its firmware.
+ */
+ error = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
+ data->regulators);
+ if (error)
+ return error;
+
+ error = devm_add_action_or_reset(dev, silead_disable_regulator, data);
+ if (error)
+ return error;
+
/* Power GPIO pin */
data->gpio_power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
if (IS_ERR(data->gpio_power)) {
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 971154cbbb03..6799cf9713f7 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -2209,14 +2209,13 @@ static void __init free_dma_resources(void)
static int __init early_amd_iommu_init(void)
{
struct acpi_table_header *ivrs_base;
- acpi_size ivrs_size;
acpi_status status;
int i, remap_cache_sz, ret = 0;
if (!amd_iommu_detected)
return -ENODEV;
- status = acpi_get_table_with_size("IVRS", 0, &ivrs_base, &ivrs_size);
+ status = acpi_get_table("IVRS", 0, &ivrs_base);
if (status == AE_NOT_FOUND)
return -ENODEV;
else if (ACPI_FAILURE(status)) {
@@ -2338,7 +2337,7 @@ static int __init early_amd_iommu_init(void)
out:
/* Don't leak any ACPI memory */
- early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size);
+ acpi_put_table(ivrs_base);
ivrs_base = NULL;
return ret;
@@ -2362,10 +2361,9 @@ out:
static bool detect_ivrs(void)
{
struct acpi_table_header *ivrs_base;
- acpi_size ivrs_size;
acpi_status status;
- status = acpi_get_table_with_size("IVRS", 0, &ivrs_base, &ivrs_size);
+ status = acpi_get_table("IVRS", 0, &ivrs_base);
if (status == AE_NOT_FOUND)
return false;
else if (ACPI_FAILURE(status)) {
@@ -2374,7 +2372,7 @@ static bool detect_ivrs(void)
return false;
}
- early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size);
+ acpi_put_table(ivrs_base);
/* Make sure ACS will be enabled during PCI probe */
pci_request_acs();
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 8c53748a769d..a88576d50740 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -68,7 +68,6 @@ DECLARE_RWSEM(dmar_global_lock);
LIST_HEAD(dmar_drhd_units);
struct acpi_table_header * __initdata dmar_tbl;
-static acpi_size dmar_tbl_size;
static int dmar_dev_scope_status = 1;
static unsigned long dmar_seq_ids[BITS_TO_LONGS(DMAR_UNITS_SUPPORTED)];
@@ -543,9 +542,7 @@ static int __init dmar_table_detect(void)
acpi_status status = AE_OK;
/* if we could find DMAR table, then there are DMAR devices */
- status = acpi_get_table_with_size(ACPI_SIG_DMAR, 0,
- (struct acpi_table_header **)&dmar_tbl,
- &dmar_tbl_size);
+ status = acpi_get_table(ACPI_SIG_DMAR, 0, &dmar_tbl);
if (ACPI_SUCCESS(status) && !dmar_tbl) {
pr_warn("Unable to map DMAR\n");
@@ -906,7 +903,7 @@ int __init detect_intel_iommu(void)
x86_init.iommu.iommu_init = intel_iommu_init;
#endif
- early_acpi_os_unmap_memory((void __iomem *)dmar_tbl, dmar_tbl_size);
+ acpi_put_table(dmar_tbl);
dmar_tbl = NULL;
up_write(&dmar_global_lock);
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index aecec6d32463..11e13c56126f 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -2565,22 +2565,22 @@ static int gigaset_post_reset(struct usb_interface *intf)
static const struct gigaset_ops gigops = {
- gigaset_write_cmd,
- gigaset_write_room,
- gigaset_chars_in_buffer,
- gigaset_brkchars,
- gigaset_init_bchannel,
- gigaset_close_bchannel,
- gigaset_initbcshw,
- gigaset_freebcshw,
- gigaset_reinitbcshw,
- gigaset_initcshw,
- gigaset_freecshw,
- gigaset_set_modem_ctrl,
- gigaset_baud_rate,
- gigaset_set_line_ctrl,
- gigaset_isoc_send_skb,
- gigaset_isoc_input,
+ .write_cmd = gigaset_write_cmd,
+ .write_room = gigaset_write_room,
+ .chars_in_buffer = gigaset_chars_in_buffer,
+ .brkchars = gigaset_brkchars,
+ .init_bchannel = gigaset_init_bchannel,
+ .close_bchannel = gigaset_close_bchannel,
+ .initbcshw = gigaset_initbcshw,
+ .freebcshw = gigaset_freebcshw,
+ .reinitbcshw = gigaset_reinitbcshw,
+ .initcshw = gigaset_initcshw,
+ .freecshw = gigaset_freecshw,
+ .set_modem_ctrl = gigaset_set_modem_ctrl,
+ .baud_rate = gigaset_baud_rate,
+ .set_line_ctrl = gigaset_set_line_ctrl,
+ .send_skb = gigaset_isoc_send_skb,
+ .handle_input = gigaset_isoc_input,
};
/* bas_gigaset_init
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
index b90776ef56ec..ab0b63a4d045 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -445,22 +445,22 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
}
static const struct gigaset_ops ops = {
- gigaset_write_cmd,
- gigaset_write_room,
- gigaset_chars_in_buffer,
- gigaset_brkchars,
- gigaset_init_bchannel,
- gigaset_close_bchannel,
- gigaset_initbcshw,
- gigaset_freebcshw,
- gigaset_reinitbcshw,
- gigaset_initcshw,
- gigaset_freecshw,
- gigaset_set_modem_ctrl,
- gigaset_baud_rate,
- gigaset_set_line_ctrl,
- gigaset_m10x_send_skb, /* asyncdata.c */
- gigaset_m10x_input, /* asyncdata.c */
+ .write_cmd = gigaset_write_cmd,
+ .write_room = gigaset_write_room,
+ .chars_in_buffer = gigaset_chars_in_buffer,
+ .brkchars = gigaset_brkchars,
+ .init_bchannel = gigaset_init_bchannel,
+ .close_bchannel = gigaset_close_bchannel,
+ .initbcshw = gigaset_initbcshw,
+ .freebcshw = gigaset_freebcshw,
+ .reinitbcshw = gigaset_reinitbcshw,
+ .initcshw = gigaset_initcshw,
+ .freecshw = gigaset_freecshw,
+ .set_modem_ctrl = gigaset_set_modem_ctrl,
+ .baud_rate = gigaset_baud_rate,
+ .set_line_ctrl = gigaset_set_line_ctrl,
+ .send_skb = gigaset_m10x_send_skb, /* asyncdata.c */
+ .handle_input = gigaset_m10x_input, /* asyncdata.c */
};
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index 5f306e2eece5..eade36dafa34 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -862,22 +862,22 @@ static int gigaset_pre_reset(struct usb_interface *intf)
}
static const struct gigaset_ops ops = {
- gigaset_write_cmd,
- gigaset_write_room,
- gigaset_chars_in_buffer,
- gigaset_brkchars,
- gigaset_init_bchannel,
- gigaset_close_bchannel,
- gigaset_initbcshw,
- gigaset_freebcshw,
- gigaset_reinitbcshw,
- gigaset_initcshw,
- gigaset_freecshw,
- gigaset_set_modem_ctrl,
- gigaset_baud_rate,
- gigaset_set_line_ctrl,
- gigaset_m10x_send_skb,
- gigaset_m10x_input,
+ .write_cmd = gigaset_write_cmd,
+ .write_room = gigaset_write_room,
+ .chars_in_buffer = gigaset_chars_in_buffer,
+ .brkchars = gigaset_brkchars,
+ .init_bchannel = gigaset_init_bchannel,
+ .close_bchannel = gigaset_close_bchannel,
+ .initbcshw = gigaset_initbcshw,
+ .freebcshw = gigaset_freebcshw,
+ .reinitbcshw = gigaset_reinitbcshw,
+ .initcshw = gigaset_initcshw,
+ .freecshw = gigaset_freecshw,
+ .set_modem_ctrl = gigaset_set_modem_ctrl,
+ .baud_rate = gigaset_baud_rate,
+ .set_line_ctrl = gigaset_set_line_ctrl,
+ .send_skb = gigaset_m10x_send_skb,
+ .handle_input = gigaset_m10x_input,
};
/*
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index bf04d2a3cf4a..2d12c6ceeb89 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -659,7 +659,7 @@ int jiftime(char *s, long mark)
static u_char tmpbuf[HISAX_STATUS_BUFSIZE];
-void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt,
+void VHiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt,
va_list args)
{
/* if head == NULL the fmt contains the full info */
@@ -669,23 +669,24 @@ void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt,
u_char *p;
isdn_ctrl ic;
int len;
+ const u_char *data;
if (!cs) {
printk(KERN_WARNING "HiSax: No CardStatus for message");
return;
}
spin_lock_irqsave(&cs->statlock, flags);
- p = tmpbuf;
if (head) {
+ p = tmpbuf;
p += jiftime(p, jiffies);
p += sprintf(p, " %s", head);
p += vsprintf(p, fmt, args);
*p++ = '\n';
*p = 0;
len = p - tmpbuf;
- p = tmpbuf;
+ data = tmpbuf;
} else {
- p = fmt;
+ data = fmt;
len = strlen(fmt);
}
if (len > HISAX_STATUS_BUFSIZE) {
@@ -699,13 +700,12 @@ void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt,
if (i >= len)
i = len;
len -= i;
- memcpy(cs->status_write, p, i);
+ memcpy(cs->status_write, data, i);
cs->status_write += i;
if (cs->status_write > cs->status_end)
cs->status_write = cs->status_buf;
- p += i;
if (len) {
- memcpy(cs->status_write, p, len);
+ memcpy(cs->status_write, data + i, len);
cs->status_write += len;
}
#ifdef KERNELSTACK_DEBUG
@@ -729,7 +729,7 @@ void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt,
}
}
-void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...)
+void HiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, ...)
{
va_list args;
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 6ead6314e6d2..338d0408b377 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -1288,9 +1288,9 @@ int jiftime(char *s, long mark);
int HiSax_command(isdn_ctrl *ic);
int HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb);
__printf(3, 4)
-void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...);
+void HiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, ...);
__printf(3, 0)
-void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args);
+void VHiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, va_list args);
void HiSax_reportcard(int cardnr, int sel);
int QuickHex(char *txt, u_char *p, int cnt);
void LogFrame(struct IsdnCardState *cs, u_char *p, int size);
diff --git a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c
index 91d57304d4d3..336523ec077c 100644
--- a/drivers/isdn/i4l/isdn_concap.c
+++ b/drivers/isdn/i4l/isdn_concap.c
@@ -80,9 +80,9 @@ static int isdn_concap_dl_disconn_req(struct concap_proto *concap)
}
struct concap_device_ops isdn_concap_reliable_dl_dops = {
- &isdn_concap_dl_data_req,
- &isdn_concap_dl_connect_req,
- &isdn_concap_dl_disconn_req
+ .data_req = &isdn_concap_dl_data_req,
+ .connect_req = &isdn_concap_dl_connect_req,
+ .disconn_req = &isdn_concap_dl_disconn_req
};
/* The following should better go into a dedicated source file such that
diff --git a/drivers/isdn/i4l/isdn_x25iface.c b/drivers/isdn/i4l/isdn_x25iface.c
index 0c5d8de41b23..ba60076e0b95 100644
--- a/drivers/isdn/i4l/isdn_x25iface.c
+++ b/drivers/isdn/i4l/isdn_x25iface.c
@@ -53,14 +53,14 @@ static int isdn_x25iface_disconn_ind(struct concap_proto *);
static struct concap_proto_ops ix25_pops = {
- &isdn_x25iface_proto_new,
- &isdn_x25iface_proto_del,
- &isdn_x25iface_proto_restart,
- &isdn_x25iface_proto_close,
- &isdn_x25iface_xmit,
- &isdn_x25iface_receive,
- &isdn_x25iface_connect_ind,
- &isdn_x25iface_disconn_ind
+ .proto_new = &isdn_x25iface_proto_new,
+ .proto_del = &isdn_x25iface_proto_del,
+ .restart = &isdn_x25iface_proto_restart,
+ .close = &isdn_x25iface_proto_close,
+ .encap_and_xmit = &isdn_x25iface_xmit,
+ .data_ind = &isdn_x25iface_receive,
+ .connect_ind = &isdn_x25iface_connect_ind,
+ .disconn_ind = &isdn_x25iface_disconn_ind
};
/* error message helper function */
diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c
index c19dd820ea9b..2aeb034d5fb9 100644
--- a/drivers/mailbox/bcm-pdc-mailbox.c
+++ b/drivers/mailbox/bcm-pdc-mailbox.c
@@ -60,7 +60,13 @@
#define RING_ENTRY_SIZE sizeof(struct dma64dd)
/* # entries in PDC dma ring */
-#define PDC_RING_ENTRIES 128
+#define PDC_RING_ENTRIES 512
+/*
+ * Minimum number of ring descriptor entries that must be free to tell mailbox
+ * framework that it can submit another request
+ */
+#define PDC_RING_SPACE_MIN 15
+
#define PDC_RING_SIZE (PDC_RING_ENTRIES * RING_ENTRY_SIZE)
/* Rings are 8k aligned */
#define RING_ALIGN_ORDER 13
@@ -93,11 +99,9 @@
* Interrupt mask and status definitions. Enable interrupts for tx and rx on
* ring 0
*/
-#define PDC_XMTINT_0 (24 + PDC_RINGSET)
#define PDC_RCVINT_0 (16 + PDC_RINGSET)
-#define PDC_XMTINTEN_0 BIT(PDC_XMTINT_0)
#define PDC_RCVINTEN_0 BIT(PDC_RCVINT_0)
-#define PDC_INTMASK (PDC_XMTINTEN_0 | PDC_RCVINTEN_0)
+#define PDC_INTMASK (PDC_RCVINTEN_0)
#define PDC_LAZY_FRAMECOUNT 1
#define PDC_LAZY_TIMEOUT 10000
#define PDC_LAZY_INT (PDC_LAZY_TIMEOUT | (PDC_LAZY_FRAMECOUNT << 24))
@@ -117,15 +121,16 @@
/*
* Sets the following bits for write to transmit control reg:
- * 0 - XmtEn - enable activity on the tx channel
* 11 - PtyChkDisable - parity check is disabled
* 20:18 - BurstLen = 3 -> 2^7 = 128 byte data reads from memory
*/
-#define PDC_TX_CTL 0x000C0801
+#define PDC_TX_CTL 0x000C0800
+
+/* Bit in tx control reg to enable tx channel */
+#define PDC_TX_ENABLE 0x1
/*
* Sets the following bits for write to receive control reg:
- * 0 - RcvEn - enable activity on the rx channel
* 7:1 - RcvOffset - size in bytes of status region at start of rx frame buf
* 9 - SepRxHdrDescEn - place start of new frames only in descriptors
* that have StartOfFrame set
@@ -135,7 +140,10 @@
* 11 - PtyChkDisable - parity check is disabled
* 20:18 - BurstLen = 3 -> 2^7 = 128 byte data reads from memory
*/
-#define PDC_RX_CTL 0x000C0E01
+#define PDC_RX_CTL 0x000C0E00
+
+/* Bit in rx control reg to enable rx channel */
+#define PDC_RX_ENABLE 0x1
#define CRYPTO_D64_RS0_CD_MASK ((PDC_RING_ENTRIES * RING_ENTRY_SIZE) - 1)
@@ -252,11 +260,29 @@ struct pdc_ring_alloc {
u32 size; /* ring allocation size in bytes */
};
+/*
+ * context associated with a receive descriptor.
+ * @rxp_ctx: opaque context associated with frame that starts at each
+ * rx ring index.
+ * @dst_sg: Scatterlist used to form reply frames beginning at a given ring
+ * index. Retained in order to unmap each sg after reply is processed.
+ * @rxin_numd: Number of rx descriptors associated with the message that starts
+ * at a descriptor index. Not set for every index. For example,
+ * if descriptor index i points to a scatterlist with 4 entries,
+ * then the next three descriptor indexes don't have a value set.
+ * @resp_hdr: Virtual address of buffer used to catch DMA rx status
+ * @resp_hdr_daddr: physical address of DMA rx status buffer
+ */
+struct pdc_rx_ctx {
+ void *rxp_ctx;
+ struct scatterlist *dst_sg;
+ u32 rxin_numd;
+ void *resp_hdr;
+ dma_addr_t resp_hdr_daddr;
+};
+
/* PDC state structure */
struct pdc_state {
- /* synchronize access to this PDC state structure */
- spinlock_t pdc_lock;
-
/* Index of the PDC whose state is in this structure instance */
u8 pdc_idx;
@@ -272,13 +298,8 @@ struct pdc_state {
unsigned int pdc_irq;
- /*
- * Last interrupt status read from PDC device. Saved in interrupt
- * handler so the handler can clear the interrupt in the device,
- * and the interrupt thread called later can know which interrupt
- * bits are active.
- */
- unsigned long intstatus;
+ /* tasklet for deferred processing after DMA rx interrupt */
+ struct tasklet_struct rx_tasklet;
/* Number of bytes of receive status prior to each rx frame */
u32 rx_status_len;
@@ -369,11 +390,7 @@ struct pdc_state {
/* Index of next rx descriptor to post. */
u32 rxout;
- /*
- * opaque context associated with frame that starts at each
- * rx ring index.
- */
- void *rxp_ctx[PDC_RING_ENTRIES];
+ struct pdc_rx_ctx rx_ctx[PDC_RING_ENTRIES];
/*
* Scatterlists used to form request and reply frames beginning at a
@@ -381,27 +398,18 @@ struct pdc_state {
* is processed
*/
struct scatterlist *src_sg[PDC_RING_ENTRIES];
- struct scatterlist *dst_sg[PDC_RING_ENTRIES];
-
- /*
- * Number of rx descriptors associated with the message that starts
- * at this descriptor index. Not set for every index. For example,
- * if descriptor index i points to a scatterlist with 4 entries, then
- * the next three descriptor indexes don't have a value set.
- */
- u32 rxin_numd[PDC_RING_ENTRIES];
-
- void *resp_hdr[PDC_RING_ENTRIES];
- dma_addr_t resp_hdr_daddr[PDC_RING_ENTRIES];
struct dentry *debugfs_stats; /* debug FS stats file for this PDC */
/* counters */
- u32 pdc_requests; /* number of request messages submitted */
- u32 pdc_replies; /* number of reply messages received */
- u32 txnobuf; /* count of tx ring full */
- u32 rxnobuf; /* count of rx ring full */
- u32 rx_oflow; /* count of rx overflows */
+ u32 pdc_requests; /* number of request messages submitted */
+ u32 pdc_replies; /* number of reply messages received */
+ u32 last_tx_not_done; /* too few tx descriptors to indicate done */
+ u32 tx_ring_full; /* unable to accept msg because tx ring full */
+ u32 rx_ring_full; /* unable to accept msg because rx ring full */
+ u32 txnobuf; /* unable to create tx descriptor */
+ u32 rxnobuf; /* unable to create rx descriptor */
+ u32 rx_oflow; /* count of rx overflows */
};
/* Global variables */
@@ -434,20 +442,33 @@ static ssize_t pdc_debugfs_read(struct file *filp, char __user *ubuf,
out_offset += snprintf(buf + out_offset, out_count - out_offset,
"SPU %u stats:\n", pdcs->pdc_idx);
out_offset += snprintf(buf + out_offset, out_count - out_offset,
- "PDC requests............%u\n",
+ "PDC requests....................%u\n",
pdcs->pdc_requests);
out_offset += snprintf(buf + out_offset, out_count - out_offset,
- "PDC responses...........%u\n",
+ "PDC responses...................%u\n",
pdcs->pdc_replies);
out_offset += snprintf(buf + out_offset, out_count - out_offset,
- "Tx err ring full........%u\n",
+ "Tx not done.....................%u\n",
+ pdcs->last_tx_not_done);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "Tx ring full....................%u\n",
+ pdcs->tx_ring_full);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "Rx ring full....................%u\n",
+ pdcs->rx_ring_full);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "Tx desc write fail. Ring full...%u\n",
pdcs->txnobuf);
out_offset += snprintf(buf + out_offset, out_count - out_offset,
- "Rx err ring full........%u\n",
+ "Rx desc write fail. Ring full...%u\n",
pdcs->rxnobuf);
out_offset += snprintf(buf + out_offset, out_count - out_offset,
- "Receive overflow........%u\n",
+ "Receive overflow................%u\n",
pdcs->rx_oflow);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "Num frags in rx ring............%u\n",
+ NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr,
+ pdcs->nrxpost));
if (out_offset > out_count)
out_offset = out_count;
@@ -480,17 +501,16 @@ static void pdc_setup_debugfs(struct pdc_state *pdcs)
if (!debugfs_dir)
debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
- pdcs->debugfs_stats = debugfs_create_file(spu_stats_name, S_IRUSR,
+ /* S_IRUSR == 0400 */
+ pdcs->debugfs_stats = debugfs_create_file(spu_stats_name, 0400,
debugfs_dir, pdcs,
&pdc_debugfs_stats);
}
static void pdc_free_debugfs(void)
{
- if (debugfs_dir && simple_empty(debugfs_dir)) {
- debugfs_remove_recursive(debugfs_dir);
- debugfs_dir = NULL;
- }
+ debugfs_remove_recursive(debugfs_dir);
+ debugfs_dir = NULL;
}
/**
@@ -505,17 +525,17 @@ pdc_build_rxd(struct pdc_state *pdcs, dma_addr_t dma_addr,
u32 buf_len, u32 flags)
{
struct device *dev = &pdcs->pdev->dev;
+ struct dma64dd *rxd = &pdcs->rxd_64[pdcs->rxout];
dev_dbg(dev,
"Writing rx descriptor for PDC %u at index %u with length %u. flags %#x\n",
pdcs->pdc_idx, pdcs->rxout, buf_len, flags);
- iowrite32(lower_32_bits(dma_addr),
- (void *)&pdcs->rxd_64[pdcs->rxout].addrlow);
- iowrite32(upper_32_bits(dma_addr),
- (void *)&pdcs->rxd_64[pdcs->rxout].addrhigh);
- iowrite32(flags, (void *)&pdcs->rxd_64[pdcs->rxout].ctrl1);
- iowrite32(buf_len, (void *)&pdcs->rxd_64[pdcs->rxout].ctrl2);
+ rxd->addrlow = cpu_to_le32(lower_32_bits(dma_addr));
+ rxd->addrhigh = cpu_to_le32(upper_32_bits(dma_addr));
+ rxd->ctrl1 = cpu_to_le32(flags);
+ rxd->ctrl2 = cpu_to_le32(buf_len);
+
/* bump ring index and return */
pdcs->rxout = NEXTRXD(pdcs->rxout, pdcs->nrxpost);
}
@@ -533,53 +553,50 @@ pdc_build_txd(struct pdc_state *pdcs, dma_addr_t dma_addr, u32 buf_len,
u32 flags)
{
struct device *dev = &pdcs->pdev->dev;
+ struct dma64dd *txd = &pdcs->txd_64[pdcs->txout];
dev_dbg(dev,
"Writing tx descriptor for PDC %u at index %u with length %u, flags %#x\n",
pdcs->pdc_idx, pdcs->txout, buf_len, flags);
- iowrite32(lower_32_bits(dma_addr),
- (void *)&pdcs->txd_64[pdcs->txout].addrlow);
- iowrite32(upper_32_bits(dma_addr),
- (void *)&pdcs->txd_64[pdcs->txout].addrhigh);
- iowrite32(flags, (void *)&pdcs->txd_64[pdcs->txout].ctrl1);
- iowrite32(buf_len, (void *)&pdcs->txd_64[pdcs->txout].ctrl2);
+ txd->addrlow = cpu_to_le32(lower_32_bits(dma_addr));
+ txd->addrhigh = cpu_to_le32(upper_32_bits(dma_addr));
+ txd->ctrl1 = cpu_to_le32(flags);
+ txd->ctrl2 = cpu_to_le32(buf_len);
/* bump ring index and return */
pdcs->txout = NEXTTXD(pdcs->txout, pdcs->ntxpost);
}
/**
- * pdc_receive() - Receive a response message from a given SPU.
+ * pdc_receive_one() - Receive a response message from a given SPU.
* @pdcs: PDC state for the SPU to receive from
- * @mssg: mailbox message to be returned to client
*
* When the return code indicates success, the response message is available in
* the receive buffers provided prior to submission of the request.
*
- * Input:
- * pdcs - PDC state structure for the SPU to be polled
- * mssg - mailbox message to be returned to client. This function sets the
- * context pointer on the message to help the client associate the
- * response with a request.
- *
* Return: PDC_SUCCESS if one or more receive descriptors was processed
* -EAGAIN indicates that no response message is available
* -EIO an error occurred
*/
static int
-pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg)
+pdc_receive_one(struct pdc_state *pdcs)
{
struct device *dev = &pdcs->pdev->dev;
+ struct mbox_controller *mbc;
+ struct mbox_chan *chan;
+ struct brcm_message mssg;
u32 len, rx_status;
u32 num_frags;
- int i;
u8 *resp_hdr; /* virtual addr of start of resp message DMA header */
u32 frags_rdy; /* number of fragments ready to read */
u32 rx_idx; /* ring index of start of receive frame */
dma_addr_t resp_hdr_daddr;
+ struct pdc_rx_ctx *rx_ctx;
- spin_lock(&pdcs->pdc_lock);
+ mbc = &pdcs->mbc;
+ chan = &mbc->chans[0];
+ mssg.type = BRCM_MESSAGE_SPU;
/*
* return if a complete response message is not yet ready.
@@ -587,47 +604,34 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg)
* to read.
*/
frags_rdy = NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr, pdcs->nrxpost);
- if ((frags_rdy == 0) || (frags_rdy < pdcs->rxin_numd[pdcs->rxin])) {
- /* See if the hw has written more fragments than we know */
- pdcs->last_rx_curr =
- (ioread32((void *)&pdcs->rxregs_64->status0) &
- CRYPTO_D64_RS0_CD_MASK) / RING_ENTRY_SIZE;
- frags_rdy = NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr,
- pdcs->nrxpost);
- if ((frags_rdy == 0) ||
- (frags_rdy < pdcs->rxin_numd[pdcs->rxin])) {
- /* No response ready */
- spin_unlock(&pdcs->pdc_lock);
- return -EAGAIN;
- }
- /* can't read descriptors/data until write index is read */
- rmb();
- }
+ if ((frags_rdy == 0) ||
+ (frags_rdy < pdcs->rx_ctx[pdcs->rxin].rxin_numd))
+ /* No response ready */
+ return -EAGAIN;
num_frags = pdcs->txin_numd[pdcs->txin];
+ WARN_ON(num_frags == 0);
+
dma_unmap_sg(dev, pdcs->src_sg[pdcs->txin],
sg_nents(pdcs->src_sg[pdcs->txin]), DMA_TO_DEVICE);
- for (i = 0; i < num_frags; i++)
- pdcs->txin = NEXTTXD(pdcs->txin, pdcs->ntxpost);
+ pdcs->txin = (pdcs->txin + num_frags) & pdcs->ntxpost;
dev_dbg(dev, "PDC %u reclaimed %d tx descriptors",
pdcs->pdc_idx, num_frags);
rx_idx = pdcs->rxin;
- num_frags = pdcs->rxin_numd[rx_idx];
+ rx_ctx = &pdcs->rx_ctx[rx_idx];
+ num_frags = rx_ctx->rxin_numd;
/* Return opaque context with result */
- mssg->ctx = pdcs->rxp_ctx[rx_idx];
- pdcs->rxp_ctx[rx_idx] = NULL;
- resp_hdr = pdcs->resp_hdr[rx_idx];
- resp_hdr_daddr = pdcs->resp_hdr_daddr[rx_idx];
- dma_unmap_sg(dev, pdcs->dst_sg[rx_idx],
- sg_nents(pdcs->dst_sg[rx_idx]), DMA_FROM_DEVICE);
-
- for (i = 0; i < num_frags; i++)
- pdcs->rxin = NEXTRXD(pdcs->rxin, pdcs->nrxpost);
+ mssg.ctx = rx_ctx->rxp_ctx;
+ rx_ctx->rxp_ctx = NULL;
+ resp_hdr = rx_ctx->resp_hdr;
+ resp_hdr_daddr = rx_ctx->resp_hdr_daddr;
+ dma_unmap_sg(dev, rx_ctx->dst_sg, sg_nents(rx_ctx->dst_sg),
+ DMA_FROM_DEVICE);
- spin_unlock(&pdcs->pdc_lock);
+ pdcs->rxin = (pdcs->rxin + num_frags) & pdcs->nrxpost;
dev_dbg(dev, "PDC %u reclaimed %d rx descriptors",
pdcs->pdc_idx, num_frags);
@@ -659,12 +663,35 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg)
dma_pool_free(pdcs->rx_buf_pool, resp_hdr, resp_hdr_daddr);
+ mbox_chan_received_data(chan, &mssg);
+
pdcs->pdc_replies++;
- /* if we read one or more rx descriptors, claim success */
- if (num_frags > 0)
- return PDC_SUCCESS;
- else
- return -EIO;
+ return PDC_SUCCESS;
+}
+
+/**
+ * pdc_receive() - Process as many responses as are available in the rx ring.
+ * @pdcs: PDC state
+ *
+ * Called within the hard IRQ.
+ * Return:
+ */
+static int
+pdc_receive(struct pdc_state *pdcs)
+{
+ int rx_status;
+
+ /* read last_rx_curr from register once */
+ pdcs->last_rx_curr =
+ (ioread32(&pdcs->rxregs_64->status0) &
+ CRYPTO_D64_RS0_CD_MASK) / RING_ENTRY_SIZE;
+
+ do {
+ /* Could be many frames ready */
+ rx_status = pdc_receive_one(pdcs);
+ } while (rx_status == PDC_SUCCESS);
+
+ return 0;
}
/**
@@ -766,8 +793,8 @@ static int pdc_tx_list_final(struct pdc_state *pdcs)
* before chip starts to process new request
*/
wmb();
- iowrite32(pdcs->rxout << 4, (void *)&pdcs->rxregs_64->ptr);
- iowrite32(pdcs->txout << 4, (void *)&pdcs->txregs_64->ptr);
+ iowrite32(pdcs->rxout << 4, &pdcs->rxregs_64->ptr);
+ iowrite32(pdcs->txout << 4, &pdcs->txregs_64->ptr);
pdcs->pdc_requests++;
return PDC_SUCCESS;
@@ -796,6 +823,7 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg,
u32 rx_pkt_cnt = 1; /* Adding a single rx buffer */
dma_addr_t daddr;
void *vaddr;
+ struct pdc_rx_ctx *rx_ctx;
rx_avail = pdcs->nrxpost - NRXDACTIVE(pdcs->rxin, pdcs->rxout,
pdcs->nrxpost);
@@ -806,7 +834,7 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg,
/* allocate a buffer for the dma rx status */
vaddr = dma_pool_zalloc(pdcs->rx_buf_pool, GFP_ATOMIC, &daddr);
- if (!vaddr)
+ if (unlikely(!vaddr))
return -ENOMEM;
/*
@@ -819,15 +847,16 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg,
/* This is always the first descriptor in the receive sequence */
flags = D64_CTRL1_SOF;
- pdcs->rxin_numd[pdcs->rx_msg_start] = 1;
+ pdcs->rx_ctx[pdcs->rx_msg_start].rxin_numd = 1;
if (unlikely(pdcs->rxout == (pdcs->nrxd - 1)))
flags |= D64_CTRL1_EOT;
- pdcs->rxp_ctx[pdcs->rxout] = ctx;
- pdcs->dst_sg[pdcs->rxout] = dst_sg;
- pdcs->resp_hdr[pdcs->rxout] = vaddr;
- pdcs->resp_hdr_daddr[pdcs->rxout] = daddr;
+ rx_ctx = &pdcs->rx_ctx[pdcs->rxout];
+ rx_ctx->rxp_ctx = ctx;
+ rx_ctx->dst_sg = dst_sg;
+ rx_ctx->resp_hdr = vaddr;
+ rx_ctx->resp_hdr_daddr = daddr;
pdc_build_rxd(pdcs, daddr, pdcs->pdc_resp_hdr_len, flags);
return PDC_SUCCESS;
}
@@ -895,7 +924,7 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg)
desc_w++;
sg = sg_next(sg);
}
- pdcs->rxin_numd[pdcs->rx_msg_start] += desc_w;
+ pdcs->rx_ctx[pdcs->rx_msg_start].rxin_numd += desc_w;
return PDC_SUCCESS;
}
@@ -903,7 +932,7 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg)
/**
* pdc_irq_handler() - Interrupt handler called in interrupt context.
* @irq: Interrupt number that has fired
- * @cookie: PDC state for DMA engine that generated the interrupt
+ * @data: device struct for DMA engine that generated the interrupt
*
* We have to clear the device interrupt status flags here. So cache the
* status for later use in the thread function. Other than that, just return
@@ -912,88 +941,39 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg)
* Return: IRQ_WAKE_THREAD if interrupt is ours
* IRQ_NONE otherwise
*/
-static irqreturn_t pdc_irq_handler(int irq, void *cookie)
+static irqreturn_t pdc_irq_handler(int irq, void *data)
{
- struct pdc_state *pdcs = cookie;
+ struct device *dev = (struct device *)data;
+ struct pdc_state *pdcs = dev_get_drvdata(dev);
u32 intstatus = ioread32(pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET);
- if (intstatus & PDC_XMTINTEN_0)
- set_bit(PDC_XMTINT_0, &pdcs->intstatus);
- if (intstatus & PDC_RCVINTEN_0)
- set_bit(PDC_RCVINT_0, &pdcs->intstatus);
+ if (unlikely(intstatus == 0))
+ return IRQ_NONE;
+
+ /* Disable interrupts until soft handler runs */
+ iowrite32(0, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET);
/* Clear interrupt flags in device */
iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET);
/* Wakeup IRQ thread */
- if (pdcs && (irq == pdcs->pdc_irq) && (intstatus & PDC_INTMASK))
- return IRQ_WAKE_THREAD;
-
- return IRQ_NONE;
+ tasklet_schedule(&pdcs->rx_tasklet);
+ return IRQ_HANDLED;
}
/**
- * pdc_irq_thread() - Function invoked on deferred thread when a DMA tx has
- * completed or data is available to receive.
- * @irq: Interrupt number
- * @cookie: PDC state for PDC that generated the interrupt
- *
- * On DMA tx complete, notify the mailbox client. On DMA rx complete, process
- * as many SPU response messages as are available and send each to the mailbox
- * client.
- *
- * Return: IRQ_HANDLED if we recognized and handled the interrupt
- * IRQ_NONE otherwise
+ * pdc_tasklet_cb() - Tasklet callback that runs the deferred processing after
+ * a DMA receive interrupt. Reenables the receive interrupt.
+ * @data: PDC state structure
*/
-static irqreturn_t pdc_irq_thread(int irq, void *cookie)
+static void pdc_tasklet_cb(unsigned long data)
{
- struct pdc_state *pdcs = cookie;
- struct mbox_controller *mbc;
- struct mbox_chan *chan;
- bool tx_int;
- bool rx_int;
- int rx_status;
- struct brcm_message mssg;
+ struct pdc_state *pdcs = (struct pdc_state *)data;
- tx_int = test_and_clear_bit(PDC_XMTINT_0, &pdcs->intstatus);
- rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus);
+ pdc_receive(pdcs);
- if (pdcs && (tx_int || rx_int)) {
- dev_dbg(&pdcs->pdev->dev,
- "%s() got irq %d with tx_int %s, rx_int %s",
- __func__, irq,
- tx_int ? "set" : "clear", rx_int ? "set" : "clear");
-
- mbc = &pdcs->mbc;
- chan = &mbc->chans[0];
-
- if (tx_int) {
- dev_dbg(&pdcs->pdev->dev, "%s(): tx done", __func__);
- /* only one frame in flight at a time */
- mbox_chan_txdone(chan, PDC_SUCCESS);
- }
- if (rx_int) {
- while (1) {
- /* Could be many frames ready */
- memset(&mssg, 0, sizeof(mssg));
- mssg.type = BRCM_MESSAGE_SPU;
- rx_status = pdc_receive(pdcs, &mssg);
- if (rx_status >= 0) {
- dev_dbg(&pdcs->pdev->dev,
- "%s(): invoking client rx cb",
- __func__);
- mbox_chan_received_data(chan, &mssg);
- } else {
- dev_dbg(&pdcs->pdev->dev,
- "%s(): no SPU response available",
- __func__);
- break;
- }
- }
- }
- return IRQ_HANDLED;
- }
- return IRQ_NONE;
+ /* reenable interrupts */
+ iowrite32(PDC_INTMASK, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET);
}
/**
@@ -1016,14 +996,14 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset)
/* Allocate tx ring */
tx.vbase = dma_pool_zalloc(pdcs->ring_pool, GFP_KERNEL, &tx.dmabase);
- if (!tx.vbase) {
+ if (unlikely(!tx.vbase)) {
err = -ENOMEM;
goto done;
}
/* Allocate rx ring */
rx.vbase = dma_pool_zalloc(pdcs->ring_pool, GFP_KERNEL, &rx.dmabase);
- if (!rx.vbase) {
+ if (unlikely(!rx.vbase)) {
err = -ENOMEM;
goto fail_dealloc;
}
@@ -1033,9 +1013,6 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset)
dev_dbg(dev, " - base DMA addr of rx ring %pad", &rx.dmabase);
dev_dbg(dev, " - base virtual addr of rx ring %p", rx.vbase);
- /* lock after ring allocation to avoid scheduling while atomic */
- spin_lock(&pdcs->pdc_lock);
-
memcpy(&pdcs->tx_ring_alloc, &tx, sizeof(tx));
memcpy(&pdcs->rx_ring_alloc, &rx, sizeof(rx));
@@ -1053,40 +1030,52 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset)
/* Tell device the base DMA address of each ring */
dma_reg = &pdcs->regs->dmaregs[ringset];
+
+ /* But first disable DMA and set curptr to 0 for both TX & RX */
+ iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control);
+ iowrite32((PDC_RX_CTL + (pdcs->rx_status_len << 1)),
+ &dma_reg->dmarcv.control);
+ iowrite32(0, &dma_reg->dmaxmt.ptr);
+ iowrite32(0, &dma_reg->dmarcv.ptr);
+
+ /* Set base DMA addresses */
iowrite32(lower_32_bits(pdcs->tx_ring_alloc.dmabase),
- (void *)&dma_reg->dmaxmt.addrlow);
+ &dma_reg->dmaxmt.addrlow);
iowrite32(upper_32_bits(pdcs->tx_ring_alloc.dmabase),
- (void *)&dma_reg->dmaxmt.addrhigh);
+ &dma_reg->dmaxmt.addrhigh);
iowrite32(lower_32_bits(pdcs->rx_ring_alloc.dmabase),
- (void *)&dma_reg->dmarcv.addrlow);
+ &dma_reg->dmarcv.addrlow);
iowrite32(upper_32_bits(pdcs->rx_ring_alloc.dmabase),
- (void *)&dma_reg->dmarcv.addrhigh);
+ &dma_reg->dmarcv.addrhigh);
+
+ /* Re-enable DMA */
+ iowrite32(PDC_TX_CTL | PDC_TX_ENABLE, &dma_reg->dmaxmt.control);
+ iowrite32((PDC_RX_CTL | PDC_RX_ENABLE | (pdcs->rx_status_len << 1)),
+ &dma_reg->dmarcv.control);
/* Initialize descriptors */
for (i = 0; i < PDC_RING_ENTRIES; i++) {
/* Every tx descriptor can be used for start of frame. */
if (i != pdcs->ntxpost) {
iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOF,
- (void *)&pdcs->txd_64[i].ctrl1);
+ &pdcs->txd_64[i].ctrl1);
} else {
/* Last descriptor in ringset. Set End of Table. */
iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOF |
- D64_CTRL1_EOT,
- (void *)&pdcs->txd_64[i].ctrl1);
+ D64_CTRL1_EOT, &pdcs->txd_64[i].ctrl1);
}
/* Every rx descriptor can be used for start of frame */
if (i != pdcs->nrxpost) {
iowrite32(D64_CTRL1_SOF,
- (void *)&pdcs->rxd_64[i].ctrl1);
+ &pdcs->rxd_64[i].ctrl1);
} else {
/* Last descriptor in ringset. Set End of Table. */
iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOT,
- (void *)&pdcs->rxd_64[i].ctrl1);
+ &pdcs->rxd_64[i].ctrl1);
}
}
- spin_unlock(&pdcs->pdc_lock);
return PDC_SUCCESS;
fail_dealloc:
@@ -1111,6 +1100,80 @@ static void pdc_ring_free(struct pdc_state *pdcs)
}
/**
+ * pdc_desc_count() - Count the number of DMA descriptors that will be required
+ * for a given scatterlist. Account for the max length of a DMA buffer.
+ * @sg: Scatterlist to be DMA'd
+ * Return: Number of descriptors required
+ */
+static u32 pdc_desc_count(struct scatterlist *sg)
+{
+ u32 cnt = 0;
+
+ while (sg) {
+ cnt += ((sg->length / PDC_DMA_BUF_MAX) + 1);
+ sg = sg_next(sg);
+ }
+ return cnt;
+}
+
+/**
+ * pdc_rings_full() - Check whether the tx ring has room for tx_cnt descriptors
+ * and the rx ring has room for rx_cnt descriptors.
+ * @pdcs: PDC state
+ * @tx_cnt: The number of descriptors required in the tx ring
+ * @rx_cnt: The number of descriptors required i the rx ring
+ *
+ * Return: true if one of the rings does not have enough space
+ * false if sufficient space is available in both rings
+ */
+static bool pdc_rings_full(struct pdc_state *pdcs, int tx_cnt, int rx_cnt)
+{
+ u32 rx_avail;
+ u32 tx_avail;
+ bool full = false;
+
+ /* Check if the tx and rx rings are likely to have enough space */
+ rx_avail = pdcs->nrxpost - NRXDACTIVE(pdcs->rxin, pdcs->rxout,
+ pdcs->nrxpost);
+ if (unlikely(rx_cnt > rx_avail)) {
+ pdcs->rx_ring_full++;
+ full = true;
+ }
+
+ if (likely(!full)) {
+ tx_avail = pdcs->ntxpost - NTXDACTIVE(pdcs->txin, pdcs->txout,
+ pdcs->ntxpost);
+ if (unlikely(tx_cnt > tx_avail)) {
+ pdcs->tx_ring_full++;
+ full = true;
+ }
+ }
+ return full;
+}
+
+/**
+ * pdc_last_tx_done() - If both the tx and rx rings have at least
+ * PDC_RING_SPACE_MIN descriptors available, then indicate that the mailbox
+ * framework can submit another message.
+ * @chan: mailbox channel to check
+ * Return: true if PDC can accept another message on this channel
+ */
+static bool pdc_last_tx_done(struct mbox_chan *chan)
+{
+ struct pdc_state *pdcs = chan->con_priv;
+ bool ret;
+
+ if (unlikely(pdc_rings_full(pdcs, PDC_RING_SPACE_MIN,
+ PDC_RING_SPACE_MIN))) {
+ pdcs->last_tx_not_done++;
+ ret = false;
+ } else {
+ ret = true;
+ }
+ return ret;
+}
+
+/**
* pdc_send_data() - mailbox send_data function
* @chan: The mailbox channel on which the data is sent. The channel
* corresponds to a DMA ringset.
@@ -1141,29 +1204,43 @@ static int pdc_send_data(struct mbox_chan *chan, void *data)
int src_nent;
int dst_nent;
int nent;
+ u32 tx_desc_req;
+ u32 rx_desc_req;
- if (mssg->type != BRCM_MESSAGE_SPU)
+ if (unlikely(mssg->type != BRCM_MESSAGE_SPU))
return -ENOTSUPP;
src_nent = sg_nents(mssg->spu.src);
- if (src_nent) {
+ if (likely(src_nent)) {
nent = dma_map_sg(dev, mssg->spu.src, src_nent, DMA_TO_DEVICE);
- if (nent == 0)
+ if (unlikely(nent == 0))
return -EIO;
}
dst_nent = sg_nents(mssg->spu.dst);
- if (dst_nent) {
+ if (likely(dst_nent)) {
nent = dma_map_sg(dev, mssg->spu.dst, dst_nent,
DMA_FROM_DEVICE);
- if (nent == 0) {
+ if (unlikely(nent == 0)) {
dma_unmap_sg(dev, mssg->spu.src, src_nent,
DMA_TO_DEVICE);
return -EIO;
}
}
- spin_lock(&pdcs->pdc_lock);
+ /*
+ * Check if the tx and rx rings have enough space. Do this prior to
+ * writing any tx or rx descriptors. Need to ensure that we do not write
+ * a partial set of descriptors, or write just rx descriptors but
+ * corresponding tx descriptors don't fit. Note that we want this check
+ * and the entire sequence of descriptor to happen without another
+ * thread getting in. The channel spin lock in the mailbox framework
+ * ensures this.
+ */
+ tx_desc_req = pdc_desc_count(mssg->spu.src);
+ rx_desc_req = pdc_desc_count(mssg->spu.dst);
+ if (unlikely(pdc_rings_full(pdcs, tx_desc_req, rx_desc_req + 1)))
+ return -ENOSPC;
/* Create rx descriptors to SPU catch response */
err = pdc_rx_list_init(pdcs, mssg->spu.dst, mssg->ctx);
@@ -1173,9 +1250,7 @@ static int pdc_send_data(struct mbox_chan *chan, void *data)
err |= pdc_tx_list_sg_add(pdcs, mssg->spu.src);
err |= pdc_tx_list_final(pdcs); /* initiate transfer */
- spin_unlock(&pdcs->pdc_lock);
-
- if (err)
+ if (unlikely(err))
dev_err(&pdcs->pdev->dev,
"%s failed with error %d", __func__, err);
@@ -1224,26 +1299,29 @@ void pdc_hw_init(struct pdc_state *pdcs)
/* initialize data structures */
pdcs->regs = (struct pdc_regs *)pdcs->pdc_reg_vbase;
pdcs->txregs_64 = (struct dma64_regs *)
- (void *)(((u8 *)pdcs->pdc_reg_vbase) +
+ (((u8 *)pdcs->pdc_reg_vbase) +
PDC_TXREGS_OFFSET + (sizeof(struct dma64) * ringset));
pdcs->rxregs_64 = (struct dma64_regs *)
- (void *)(((u8 *)pdcs->pdc_reg_vbase) +
+ (((u8 *)pdcs->pdc_reg_vbase) +
PDC_RXREGS_OFFSET + (sizeof(struct dma64) * ringset));
pdcs->ntxd = PDC_RING_ENTRIES;
pdcs->nrxd = PDC_RING_ENTRIES;
pdcs->ntxpost = PDC_RING_ENTRIES - 1;
pdcs->nrxpost = PDC_RING_ENTRIES - 1;
- pdcs->regs->intmask = 0;
+ iowrite32(0, &pdcs->regs->intmask);
dma_reg = &pdcs->regs->dmaregs[ringset];
- iowrite32(0, (void *)&dma_reg->dmaxmt.ptr);
- iowrite32(0, (void *)&dma_reg->dmarcv.ptr);
- iowrite32(PDC_TX_CTL, (void *)&dma_reg->dmaxmt.control);
+ /* Configure DMA but will enable later in pdc_ring_init() */
+ iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control);
iowrite32(PDC_RX_CTL + (pdcs->rx_status_len << 1),
- (void *)&dma_reg->dmarcv.control);
+ &dma_reg->dmarcv.control);
+
+ /* Reset current index pointers after making sure DMA is disabled */
+ iowrite32(0, &dma_reg->dmaxmt.ptr);
+ iowrite32(0, &dma_reg->dmarcv.ptr);
if (pdcs->pdc_resp_hdr_len == PDC_SPU2_RESP_HDR_LEN)
iowrite32(PDC_CKSUM_CTRL,
@@ -1251,6 +1329,21 @@ void pdc_hw_init(struct pdc_state *pdcs)
}
/**
+ * pdc_hw_disable() - Disable the tx and rx control in the hw.
+ * @pdcs: PDC state structure
+ *
+ */
+static void pdc_hw_disable(struct pdc_state *pdcs)
+{
+ struct dma64 *dma_reg;
+
+ dma_reg = &pdcs->regs->dmaregs[PDC_RINGSET];
+ iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control);
+ iowrite32(PDC_RX_CTL + (pdcs->rx_status_len << 1),
+ &dma_reg->dmarcv.control);
+}
+
+/**
* pdc_rx_buf_pool_create() - Pool of receive buffers used to catch the metadata
* header returned with each response message.
* @pdcs: PDC state structure
@@ -1301,8 +1394,6 @@ static int pdc_interrupts_init(struct pdc_state *pdcs)
struct device_node *dn = pdev->dev.of_node;
int err;
- pdcs->intstatus = 0;
-
/* interrupt configuration */
iowrite32(PDC_INTMASK, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET);
iowrite32(PDC_LAZY_INT, pdcs->pdc_reg_vbase + PDC_RCVLAZY0_OFFSET);
@@ -1311,11 +1402,11 @@ static int pdc_interrupts_init(struct pdc_state *pdcs)
pdcs->pdc_irq = irq_of_parse_and_map(dn, 0);
dev_dbg(dev, "pdc device %s irq %u for pdcs %p",
dev_name(dev), pdcs->pdc_irq, pdcs);
- err = devm_request_threaded_irq(dev, pdcs->pdc_irq,
- pdc_irq_handler,
- pdc_irq_thread, 0, dev_name(dev), pdcs);
+
+ err = devm_request_irq(dev, pdcs->pdc_irq, pdc_irq_handler, 0,
+ dev_name(dev), dev);
if (err) {
- dev_err(dev, "threaded tx IRQ %u request failed with err %d\n",
+ dev_err(dev, "IRQ %u request failed with err %d\n",
pdcs->pdc_irq, err);
return err;
}
@@ -1324,6 +1415,7 @@ static int pdc_interrupts_init(struct pdc_state *pdcs)
static const struct mbox_chan_ops pdc_mbox_chan_ops = {
.send_data = pdc_send_data,
+ .last_tx_done = pdc_last_tx_done,
.startup = pdc_startup,
.shutdown = pdc_shutdown
};
@@ -1356,8 +1448,9 @@ static int pdc_mb_init(struct pdc_state *pdcs)
if (!mbc->chans)
return -ENOMEM;
- mbc->txdone_irq = true;
- mbc->txdone_poll = false;
+ mbc->txdone_irq = false;
+ mbc->txdone_poll = true;
+ mbc->txpoll_period = 1;
for (chan_index = 0; chan_index < mbc->num_chans; chan_index++)
mbc->chans[chan_index].con_priv = pdcs;
@@ -1427,7 +1520,6 @@ static int pdc_probe(struct platform_device *pdev)
goto cleanup;
}
- spin_lock_init(&pdcs->pdc_lock);
pdcs->pdev = pdev;
platform_set_drvdata(pdev, pdcs);
pdcs->pdc_idx = pdcg.num_spu;
@@ -1473,6 +1565,9 @@ static int pdc_probe(struct platform_device *pdev)
pdc_hw_init(pdcs);
+ /* Init tasklet for deferred DMA rx processing */
+ tasklet_init(&pdcs->rx_tasklet, pdc_tasklet_cb, (unsigned long)pdcs);
+
err = pdc_interrupts_init(pdcs);
if (err)
goto cleanup_buf_pool;
@@ -1489,6 +1584,7 @@ static int pdc_probe(struct platform_device *pdev)
return PDC_SUCCESS;
cleanup_buf_pool:
+ tasklet_kill(&pdcs->rx_tasklet);
dma_pool_destroy(pdcs->rx_buf_pool);
cleanup_ring_pool:
@@ -1504,6 +1600,10 @@ static int pdc_remove(struct platform_device *pdev)
pdc_free_debugfs();
+ tasklet_kill(&pdcs->rx_tasklet);
+
+ pdc_hw_disable(pdcs);
+
mbox_controller_unregister(&pdcs->mbc);
dma_pool_destroy(pdcs->rx_buf_pool);
diff --git a/drivers/mailbox/mailbox-sti.c b/drivers/mailbox/mailbox-sti.c
index a334db5c9f1c..41bcd339b68a 100644
--- a/drivers/mailbox/mailbox-sti.c
+++ b/drivers/mailbox/mailbox-sti.c
@@ -403,6 +403,7 @@ static const struct of_device_id sti_mailbox_match[] = {
},
{ }
};
+MODULE_DEVICE_TABLE(of, sti_mailbox_match);
static int sti_mbox_probe(struct platform_device *pdev)
{
diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c
index 9ca96e9db6bf..9c79f8019d2a 100644
--- a/drivers/mailbox/mailbox-test.c
+++ b/drivers/mailbox/mailbox-test.c
@@ -11,12 +11,14 @@
#include <linux/debugfs.h>
#include <linux/err.h>
+#include <linux/fs.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mailbox_client.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
@@ -39,6 +41,8 @@ struct mbox_test_device {
char *signal;
char *message;
spinlock_t lock;
+ wait_queue_head_t waitq;
+ struct fasync_struct *async_queue;
};
static ssize_t mbox_test_signal_write(struct file *filp,
@@ -81,6 +85,13 @@ static const struct file_operations mbox_test_signal_ops = {
.llseek = generic_file_llseek,
};
+static int mbox_test_message_fasync(int fd, struct file *filp, int on)
+{
+ struct mbox_test_device *tdev = filp->private_data;
+
+ return fasync_helper(fd, filp, on, &tdev->async_queue);
+}
+
static ssize_t mbox_test_message_write(struct file *filp,
const char __user *userbuf,
size_t count, loff_t *ppos)
@@ -138,6 +149,20 @@ out:
return ret < 0 ? ret : count;
}
+static bool mbox_test_message_data_ready(struct mbox_test_device *tdev)
+{
+ unsigned char data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tdev->lock, flags);
+ data = tdev->rx_buffer[0];
+ spin_unlock_irqrestore(&tdev->lock, flags);
+
+ if (data != '\0')
+ return true;
+ return false;
+}
+
static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
size_t count, loff_t *ppos)
{
@@ -147,6 +172,8 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
int l = 0;
int ret;
+ DECLARE_WAITQUEUE(wait, current);
+
touser = kzalloc(MBOX_HEXDUMP_MAX_LEN + 1, GFP_KERNEL);
if (!touser)
return -ENOMEM;
@@ -155,15 +182,29 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
ret = snprintf(touser, 20, "<NO RX CAPABILITY>\n");
ret = simple_read_from_buffer(userbuf, count, ppos,
touser, ret);
- goto out;
+ goto kfree_err;
}
- if (tdev->rx_buffer[0] == '\0') {
- ret = snprintf(touser, 9, "<EMPTY>\n");
- ret = simple_read_from_buffer(userbuf, count, ppos,
- touser, ret);
- goto out;
- }
+ add_wait_queue(&tdev->waitq, &wait);
+
+ do {
+ __set_current_state(TASK_INTERRUPTIBLE);
+
+ if (mbox_test_message_data_ready(tdev))
+ break;
+
+ if (filp->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ goto waitq_err;
+ }
+
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ goto waitq_err;
+ }
+ schedule();
+
+ } while (1);
spin_lock_irqsave(&tdev->lock, flags);
@@ -185,14 +226,31 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
spin_unlock_irqrestore(&tdev->lock, flags);
ret = simple_read_from_buffer(userbuf, count, ppos, touser, MBOX_HEXDUMP_MAX_LEN);
-out:
+waitq_err:
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&tdev->waitq, &wait);
+kfree_err:
kfree(touser);
return ret;
}
+static unsigned int
+mbox_test_message_poll(struct file *filp, struct poll_table_struct *wait)
+{
+ struct mbox_test_device *tdev = filp->private_data;
+
+ poll_wait(filp, &tdev->waitq, wait);
+
+ if (mbox_test_message_data_ready(tdev))
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
static const struct file_operations mbox_test_message_ops = {
.write = mbox_test_message_write,
.read = mbox_test_message_read,
+ .fasync = mbox_test_message_fasync,
+ .poll = mbox_test_message_poll,
.open = simple_open,
.llseek = generic_file_llseek,
};
@@ -234,6 +292,10 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message)
memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN);
}
spin_unlock_irqrestore(&tdev->lock, flags);
+
+ wake_up_interruptible(&tdev->waitq);
+
+ kill_fasync(&tdev->async_queue, SIGIO, POLL_IN);
}
static void mbox_test_prepare_message(struct mbox_client *client, void *message)
@@ -290,6 +352,7 @@ static int mbox_test_probe(struct platform_device *pdev)
{
struct mbox_test_device *tdev;
struct resource *res;
+ resource_size_t size;
int ret;
tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
@@ -298,14 +361,21 @@ static int mbox_test_probe(struct platform_device *pdev)
/* It's okay for MMIO to be NULL */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ size = resource_size(res);
tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(tdev->tx_mmio))
+ if (PTR_ERR(tdev->tx_mmio) == -EBUSY)
+ /* if reserved area in SRAM, try just ioremap */
+ tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size);
+ else if (IS_ERR(tdev->tx_mmio))
tdev->tx_mmio = NULL;
/* If specified, second reg entry is Rx MMIO */
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ size = resource_size(res);
tdev->rx_mmio = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(tdev->rx_mmio))
+ if (PTR_ERR(tdev->rx_mmio) == -EBUSY)
+ tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size);
+ else if (IS_ERR(tdev->rx_mmio))
tdev->rx_mmio = tdev->tx_mmio;
tdev->tx_channel = mbox_test_request_channel(pdev, "tx");
@@ -334,6 +404,7 @@ static int mbox_test_probe(struct platform_device *pdev)
if (ret)
return ret;
+ init_waitqueue_head(&tdev->waitq);
dev_info(&pdev->dev, "Successfully registered\n");
return 0;
@@ -357,6 +428,7 @@ static const struct of_device_id mbox_test_match[] = {
{ .compatible = "mailbox-test" },
{},
};
+MODULE_DEVICE_TABLE(of, mbox_test_match);
static struct platform_driver mbox_test_driver = {
.driver = {
diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c
index 1f32688c312d..dd9ecd354a3e 100644
--- a/drivers/mailbox/pcc.c
+++ b/drivers/mailbox/pcc.c
@@ -447,7 +447,6 @@ static int pcc_parse_subspace_irq(int id,
*/
static int __init acpi_pcc_probe(void)
{
- acpi_size pcct_tbl_header_size;
struct acpi_table_header *pcct_tbl;
struct acpi_subtable_header *pcct_entry;
struct acpi_table_pcct *acpi_pcct_tbl;
@@ -456,9 +455,7 @@ static int __init acpi_pcc_probe(void)
acpi_status status = AE_OK;
/* Search for PCCT */
- status = acpi_get_table_with_size(ACPI_SIG_PCCT, 0,
- &pcct_tbl,
- &pcct_tbl_header_size);
+ status = acpi_get_table(ACPI_SIG_PCCT, 0, &pcct_tbl);
if (ACPI_FAILURE(status) || !pcct_tbl) {
pr_warn("PCCT header not found.\n");
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 1ed0584f494e..4ce3b6f11830 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -40,6 +40,22 @@ config MFD_ACT8945A
linear regulators, along with a complete ActivePath battery
charger.
+config MFD_SUN4I_GPADC
+ tristate "Allwinner sunxi platforms' GPADC MFD driver"
+ select MFD_CORE
+ select REGMAP_MMIO
+ select REGMAP_IRQ
+ depends on ARCH_SUNXI || COMPILE_TEST
+ help
+ Select this to get support for Allwinner SoCs (A10, A13 and A31) ADC.
+ This driver will only map the hardware interrupt and registers, you
+ have to select individual drivers based on this MFD to be able to use
+ the ADC or the thermal sensor. This will try to probe the ADC driver
+ sun4i-gpadc-iio and the hwmon driver iio_hwmon.
+
+ To compile this driver as a module, choose M here: the module will be
+ called sun4i-gpadc.
+
config MFD_AS3711
bool "AMS AS3711"
select MFD_CORE
@@ -293,6 +309,7 @@ config MFD_DLN2
config MFD_EXYNOS_LPASS
tristate "Samsung Exynos SoC Low Power Audio Subsystem"
+ depends on ARCH_EXYNOS || COMPILE_TEST
select MFD_CORE
select REGMAP_MMIO
help
@@ -563,7 +580,7 @@ config MFD_MAX14577
config MFD_MAX77620
bool "Maxim Semiconductor MAX77620 and MAX20024 PMIC Support"
depends on I2C=y
- depends on OF
+ depends on OF || COMPILE_TEST
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
@@ -578,7 +595,7 @@ config MFD_MAX77620
config MFD_MAX77686
tristate "Maxim Semiconductor MAX77686/802 PMIC Support"
depends on I2C
- depends on OF
+ depends on OF || COMPILE_TEST
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
@@ -877,7 +894,8 @@ config MFD_RN5T618
select MFD_CORE
select REGMAP_I2C
help
- Say yes here to add support for the Ricoh RN5T567 or R5T618 PMIC.
+ Say yes here to add support for the Ricoh RN5T567,
+ RN5T618, RC5T619 PMIC.
This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the
functionality of the device.
@@ -951,7 +969,7 @@ config MFD_SMSC
config ABX500_CORE
bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
- default y if ARCH_U300 || ARCH_U8500
+ default y if ARCH_U300 || ARCH_U8500 || COMPILE_TEST
help
Say yes here if you have the ABX500 Mixed Signal IC family
chips. This core driver expose register access functions.
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 7bb5a50127cb..dda4d4f73ad7 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -211,3 +211,4 @@ obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o
obj-$(CONFIG_MFD_MT6397) += mt6397-core.o
obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
+obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c
index 6a5a98806cb8..099635bed188 100644
--- a/drivers/mfd/ab3100-core.c
+++ b/drivers/mfd/ab3100-core.c
@@ -12,7 +12,7 @@
#include <linux/notifier.h>
#include <linux/slab.h>
#include <linux/err.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/interrupt.h>
@@ -628,20 +628,10 @@ static void ab3100_setup_debugfs(struct ab3100 *ab3100)
exit_no_debugfs:
return;
}
-static inline void ab3100_remove_debugfs(void)
-{
- debugfs_remove(ab3100_set_reg_file);
- debugfs_remove(ab3100_get_reg_file);
- debugfs_remove(ab3100_reg_file);
- debugfs_remove(ab3100_dir);
-}
#else
static inline void ab3100_setup_debugfs(struct ab3100 *ab3100)
{
}
-static inline void ab3100_remove_debugfs(void)
-{
-}
#endif
/*
@@ -949,45 +939,22 @@ static int ab3100_probe(struct i2c_client *client,
return err;
}
-static int ab3100_remove(struct i2c_client *client)
-{
- struct ab3100 *ab3100 = i2c_get_clientdata(client);
-
- /* Unregister subdevices */
- mfd_remove_devices(&client->dev);
- ab3100_remove_debugfs();
- i2c_unregister_device(ab3100->testreg_client);
- return 0;
-}
-
static const struct i2c_device_id ab3100_id[] = {
{ "ab3100", 0 },
{ }
};
-MODULE_DEVICE_TABLE(i2c, ab3100_id);
static struct i2c_driver ab3100_driver = {
.driver = {
- .name = "ab3100",
+ .name = "ab3100",
+ .suppress_bind_attrs = true,
},
.id_table = ab3100_id,
.probe = ab3100_probe,
- .remove = ab3100_remove,
};
static int __init ab3100_i2c_init(void)
{
return i2c_add_driver(&ab3100_driver);
}
-
-static void __exit ab3100_i2c_exit(void)
-{
- i2c_del_driver(&ab3100_driver);
-}
-
subsys_initcall(ab3100_i2c_init);
-module_exit(ab3100_i2c_exit);
-
-MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
-MODULE_DESCRIPTION("AB3100 core driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 589eebfc13df..6e00124cef01 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -14,7 +14,7 @@
#include <linux/irqdomain.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/abx500.h>
@@ -123,6 +123,10 @@ static DEFINE_SPINLOCK(on_stat_lock);
static u8 turn_on_stat_mask = 0xFF;
static u8 turn_on_stat_set;
static bool no_bm; /* No battery management */
+/*
+ * not really modular, but the easiest way to keep compat with existing
+ * bootargs behaviour is to continue using module_param here.
+ */
module_param(no_bm, bool, S_IRUGO);
#define AB9540_MODEM_CTRL2_REG 0x23
@@ -1324,25 +1328,6 @@ static int ab8500_probe(struct platform_device *pdev)
return ret;
}
-static int ab8500_remove(struct platform_device *pdev)
-{
- struct ab8500 *ab8500 = platform_get_drvdata(pdev);
-
- if (((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
- ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500))
- sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
- else
- sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
-
- if ((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
- ab8500->chip_id >= AB8500_CUT2P0)
- sysfs_remove_group(&ab8500->dev->kobj, &ab8505_attr_group);
-
- mfd_remove_devices(ab8500->dev);
-
- return 0;
-}
-
static const struct platform_device_id ab8500_id[] = {
{ "ab8500-core", AB8500_VERSION_AB8500 },
{ "ab8505-i2c", AB8500_VERSION_AB8505 },
@@ -1354,9 +1339,9 @@ static const struct platform_device_id ab8500_id[] = {
static struct platform_driver ab8500_core_driver = {
.driver = {
.name = "ab8500-core",
+ .suppress_bind_attrs = true,
},
.probe = ab8500_probe,
- .remove = ab8500_remove,
.id_table = ab8500_id,
};
@@ -1364,14 +1349,4 @@ static int __init ab8500_core_init(void)
{
return platform_driver_register(&ab8500_core_driver);
}
-
-static void __exit ab8500_core_exit(void)
-{
- platform_driver_unregister(&ab8500_core_driver);
-}
core_initcall(ab8500_core_init);
-module_exit(ab8500_core_exit);
-
-MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent");
-MODULE_DESCRIPTION("AB8500 MFD core");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index acf6c00b14b9..c1c815241e02 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -74,7 +74,7 @@
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/debugfs.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
@@ -3234,33 +3234,16 @@ err:
return -ENOMEM;
}
-static int ab8500_debug_remove(struct platform_device *plf)
-{
- debugfs_remove_recursive(ab8500_dir);
-
- return 0;
-}
-
static struct platform_driver ab8500_debug_driver = {
.driver = {
.name = "ab8500-debug",
+ .suppress_bind_attrs = true,
},
.probe = ab8500_debug_probe,
- .remove = ab8500_debug_remove
};
static int __init ab8500_debug_init(void)
{
return platform_driver_register(&ab8500_debug_driver);
}
-
-static void __exit ab8500_debug_exit(void)
-{
- platform_driver_unregister(&ab8500_debug_driver);
-}
subsys_initcall(ab8500_debug_init);
-module_exit(ab8500_debug_exit);
-
-MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com");
-MODULE_DESCRIPTION("AB8500 DEBUG");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index 97dcadc8fa8b..f4e94869d612 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -5,9 +5,9 @@
* Author: Arun R Murthy <arun.murthy@stericsson.com>
* Author: Daniel Willerud <daniel.willerud@stericsson.com>
* Author: Johan Palsson <johan.palsson@stericsson.com>
+ * Author: M'boumba Cedric Madianga
*/
#include <linux/init.h>
-#include <linux/module.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
@@ -1054,11 +1054,7 @@ static int __init ab8500_gpadc_init(void)
{
return platform_driver_register(&ab8500_gpadc_driver);
}
-
-static void __exit ab8500_gpadc_exit(void)
-{
- platform_driver_unregister(&ab8500_gpadc_driver);
-}
+subsys_initcall_sync(ab8500_gpadc_init);
/**
* ab8540_gpadc_get_otp() - returns OTP values
@@ -1077,14 +1073,3 @@ void ab8540_gpadc_get_otp(struct ab8500_gpadc *gpadc,
*ibat_l = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_lo;
*ibat_h = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_hi;
}
-
-subsys_initcall_sync(ab8500_gpadc_init);
-module_exit(ab8500_gpadc_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Arun R Murthy");
-MODULE_AUTHOR("Daniel Willerud");
-MODULE_AUTHOR("Johan Palsson");
-MODULE_AUTHOR("M'boumba Cedric Madianga");
-MODULE_ALIAS("platform:ab8500_gpadc");
-MODULE_DESCRIPTION("AB8500 GPADC driver");
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index 207cc497958a..80c0efa66ac1 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -1,11 +1,14 @@
/*
+ * AB8500 system control driver
+ *
* Copyright (C) ST-Ericsson SA 2010
* Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> for ST Ericsson.
* License terms: GNU General Public License (GPL) version 2
*/
#include <linux/err.h>
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/reboot.h>
@@ -158,7 +161,3 @@ static int __init ab8500_sysctrl_init(void)
return platform_driver_register(&ab8500_sysctrl_driver);
}
arch_initcall(ab8500_sysctrl_init);
-
-MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com");
-MODULE_DESCRIPTION("AB8500 system control driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/abx500-core.c b/drivers/mfd/abx500-core.c
index fe418995108c..0d3846a4767c 100644
--- a/drivers/mfd/abx500-core.c
+++ b/drivers/mfd/abx500-core.c
@@ -8,7 +8,8 @@
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/err.h>
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
#include <linux/mfd/abx500.h>
static LIST_HEAD(abx500_list);
@@ -150,7 +151,3 @@ int abx500_startup_irq_enabled(struct device *dev, unsigned int irq)
return -ENOTSUPP;
}
EXPORT_SYMBOL(abx500_startup_irq_enabled);
-
-MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>");
-MODULE_DESCRIPTION("ABX500 core driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index 41767f7239bb..b6d4bc63c426 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -1553,6 +1553,7 @@ EXPORT_SYMBOL_GPL(arizona_dev_init);
int arizona_dev_exit(struct arizona *arizona)
{
+ disable_irq(arizona->irq);
pm_runtime_disable(arizona->dev);
regulator_disable(arizona->dcvdd);
diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c
index 5e18d3c77582..2e01975f042d 100644
--- a/drivers/mfd/arizona-irq.c
+++ b/drivers/mfd/arizona-irq.c
@@ -398,10 +398,10 @@ err_ctrlif:
err_boot_done:
free_irq(arizona->irq, arizona);
err_main_irq:
- regmap_del_irq_chip(irq_create_mapping(arizona->virq, 1),
+ regmap_del_irq_chip(irq_find_mapping(arizona->virq, 1),
arizona->irq_chip);
err_aod:
- regmap_del_irq_chip(irq_create_mapping(arizona->virq, 0),
+ regmap_del_irq_chip(irq_find_mapping(arizona->virq, 0),
arizona->aod_irq_chip);
err:
return ret;
@@ -413,9 +413,9 @@ int arizona_irq_exit(struct arizona *arizona)
free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR),
arizona);
free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE), arizona);
- regmap_del_irq_chip(irq_create_mapping(arizona->virq, 1),
+ regmap_del_irq_chip(irq_find_mapping(arizona->virq, 1),
arizona->irq_chip);
- regmap_del_irq_chip(irq_create_mapping(arizona->virq, 0),
+ regmap_del_irq_chip(irq_find_mapping(arizona->virq, 0),
arizona->aod_irq_chip);
free_irq(arizona->irq, arizona);
diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c
index b1b865822c07..d35a5fe6c950 100644
--- a/drivers/mfd/axp20x-i2c.c
+++ b/drivers/mfd/axp20x-i2c.c
@@ -69,10 +69,11 @@ static const struct of_device_id axp20x_i2c_of_match[] = {
};
MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match);
-/*
- * This is useless for OF-enabled devices, but it is needed by I2C subsystem
- */
static const struct i2c_device_id axp20x_i2c_id[] = {
+ { "axp152", 0 },
+ { "axp202", 0 },
+ { "axp209", 0 },
+ { "axp221", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index ba130be32e61..ed918de84238 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -98,6 +98,7 @@ static const struct regmap_range axp22x_volatile_ranges[] = {
regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP20X_PWR_OP_MODE),
regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
regmap_reg_range(AXP22X_GPIO_STATE, AXP22X_GPIO_STATE),
+ regmap_reg_range(AXP22X_PMIC_ADC_H, AXP20X_IPSOUT_V_HIGH_L),
regmap_reg_range(AXP20X_FG_RES, AXP20X_FG_RES),
};
@@ -135,6 +136,7 @@ static const struct regmap_range axp806_writeable_ranges[] = {
regmap_reg_range(AXP806_PWR_OUT_CTRL1, AXP806_CLDO3_V_CTRL),
regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ2_EN),
regmap_reg_range(AXP20X_IRQ1_STATE, AXP20X_IRQ2_STATE),
+ regmap_reg_range(AXP806_REG_ADDR_EXT, AXP806_REG_ADDR_EXT),
};
static const struct regmap_range axp806_volatile_ranges[] = {
@@ -305,7 +307,7 @@ static const struct regmap_config axp806_regmap_config = {
.val_bits = 8,
.wr_table = &axp806_writeable_table,
.volatile_table = &axp806_volatile_table,
- .max_register = AXP806_VREF_TEMP_WARN_L,
+ .max_register = AXP806_REG_ADDR_EXT,
.cache_type = REGCACHE_RBTREE,
};
diff --git a/drivers/mfd/bcm590xx.c b/drivers/mfd/bcm590xx.c
index 0d76d690176b..c572a35a9341 100644
--- a/drivers/mfd/bcm590xx.c
+++ b/drivers/mfd/bcm590xx.c
@@ -67,7 +67,7 @@ static int bcm590xx_i2c_probe(struct i2c_client *i2c_pri,
/* Secondary I2C slave address is the base address with A(2) asserted */
bcm590xx->i2c_sec = i2c_new_dummy(i2c_pri->adapter,
i2c_pri->addr | BIT(2));
- if (IS_ERR_OR_NULL(bcm590xx->i2c_sec)) {
+ if (!bcm590xx->i2c_sec) {
dev_err(&i2c_pri->dev, "failed to add secondary I2C device\n");
return -ENODEV;
}
diff --git a/drivers/mfd/cs47l24-tables.c b/drivers/mfd/cs47l24-tables.c
index f6b78aafdb55..c090974340ad 100644
--- a/drivers/mfd/cs47l24-tables.c
+++ b/drivers/mfd/cs47l24-tables.c
@@ -292,6 +292,7 @@ static const struct reg_default cs47l24_reg_default[] = {
{ 0x00000502, 0x0000 }, /* R1282 - AIF1 Rx Pin Ctrl */
{ 0x00000503, 0x0000 }, /* R1283 - AIF1 Rate Ctrl */
{ 0x00000504, 0x0000 }, /* R1284 - AIF1 Format */
+ { 0x00000505, 0x0040 }, /* R1285 - AIF1 Tx BCLK Rate */
{ 0x00000506, 0x0040 }, /* R1286 - AIF1 Rx BCLK Rate */
{ 0x00000507, 0x1818 }, /* R1287 - AIF1 Frame Ctrl 1 */
{ 0x00000508, 0x1818 }, /* R1288 - AIF1 Frame Ctrl 2 */
@@ -318,6 +319,7 @@ static const struct reg_default cs47l24_reg_default[] = {
{ 0x00000542, 0x0000 }, /* R1346 - AIF2 Rx Pin Ctrl */
{ 0x00000543, 0x0000 }, /* R1347 - AIF2 Rate Ctrl */
{ 0x00000544, 0x0000 }, /* R1348 - AIF2 Format */
+ { 0x00000545, 0x0040 }, /* R1349 - AIF2 Tx BCLK Rate */
{ 0x00000546, 0x0040 }, /* R1350 - AIF2 Rx BCLK Rate */
{ 0x00000547, 0x1818 }, /* R1351 - AIF2 Frame Ctrl 1 */
{ 0x00000548, 0x1818 }, /* R1352 - AIF2 Frame Ctrl 2 */
@@ -340,6 +342,7 @@ static const struct reg_default cs47l24_reg_default[] = {
{ 0x00000582, 0x0000 }, /* R1410 - AIF3 Rx Pin Ctrl */
{ 0x00000583, 0x0000 }, /* R1411 - AIF3 Rate Ctrl */
{ 0x00000584, 0x0000 }, /* R1412 - AIF3 Format */
+ { 0x00000585, 0x0040 }, /* R1413 - AIF3 Tx BCLK Rate */
{ 0x00000586, 0x0040 }, /* R1414 - AIF3 Rx BCLK Rate */
{ 0x00000587, 0x1818 }, /* R1415 - AIF3 Frame Ctrl 1 */
{ 0x00000588, 0x1818 }, /* R1416 - AIF3 Frame Ctrl 2 */
@@ -923,6 +926,7 @@ static bool cs47l24_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_AIF1_RX_PIN_CTRL:
case ARIZONA_AIF1_RATE_CTRL:
case ARIZONA_AIF1_FORMAT:
+ case ARIZONA_AIF1_TX_BCLK_RATE:
case ARIZONA_AIF1_RX_BCLK_RATE:
case ARIZONA_AIF1_FRAME_CTRL_1:
case ARIZONA_AIF1_FRAME_CTRL_2:
@@ -949,6 +953,7 @@ static bool cs47l24_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_AIF2_RX_PIN_CTRL:
case ARIZONA_AIF2_RATE_CTRL:
case ARIZONA_AIF2_FORMAT:
+ case ARIZONA_AIF2_TX_BCLK_RATE:
case ARIZONA_AIF2_RX_BCLK_RATE:
case ARIZONA_AIF2_FRAME_CTRL_1:
case ARIZONA_AIF2_FRAME_CTRL_2:
@@ -971,6 +976,7 @@ static bool cs47l24_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_AIF3_RX_PIN_CTRL:
case ARIZONA_AIF3_RATE_CTRL:
case ARIZONA_AIF3_FORMAT:
+ case ARIZONA_AIF3_TX_BCLK_RATE:
case ARIZONA_AIF3_RX_BCLK_RATE:
case ARIZONA_AIF3_FRAME_CTRL_1:
case ARIZONA_AIF3_FRAME_CTRL_2:
diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c
index dff2f19296b8..4d0a5f38038a 100644
--- a/drivers/mfd/davinci_voicecodec.c
+++ b/drivers/mfd/davinci_voicecodec.c
@@ -32,6 +32,7 @@
#include <sound/pcm.h>
#include <linux/mfd/davinci_voicecodec.h>
+#include <mach/hardware.h>
static const struct regmap_config davinci_vc_regmap = {
.reg_bits = 32,
diff --git a/drivers/mfd/fsl-imx25-tsadc.c b/drivers/mfd/fsl-imx25-tsadc.c
index 77b2675cf8f5..ac430a396a89 100644
--- a/drivers/mfd/fsl-imx25-tsadc.c
+++ b/drivers/mfd/fsl-imx25-tsadc.c
@@ -187,6 +187,7 @@ static const struct of_device_id mx25_tsadc_ids[] = {
{ .compatible = "fsl,imx25-tsadc" },
{ /* Sentinel */ }
};
+MODULE_DEVICE_TABLE(of, mx25_tsadc_ids);
static struct platform_driver mx25_tsadc_driver = {
.driver = {
diff --git a/drivers/mfd/hi655x-pmic.c b/drivers/mfd/hi655x-pmic.c
index 0fc62995695b..ba706adee38b 100644
--- a/drivers/mfd/hi655x-pmic.c
+++ b/drivers/mfd/hi655x-pmic.c
@@ -169,6 +169,7 @@ static const struct of_device_id hi655x_pmic_match[] = {
{ .compatible = "hisilicon,hi655x-pmic", },
{},
};
+MODULE_DEVICE_TABLE(of, hi655x_pmic_match);
static struct platform_driver hi655x_pmic_driver = {
.driver = {
diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c
index 9ff243970e93..78dbcf8b0bef 100644
--- a/drivers/mfd/intel-lpss-pci.c
+++ b/drivers/mfd/intel-lpss-pci.c
@@ -41,6 +41,7 @@ static int intel_lpss_pci_probe(struct pci_dev *pdev,
/* Probably it is enough to set this for iDMA capable devices only */
pci_set_master(pdev);
+ pci_try_set_mwi(pdev);
ret = intel_lpss_probe(&pdev->dev, info);
if (ret)
diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c
index f9a8c5203873..699c8c7c9052 100644
--- a/drivers/mfd/intel_soc_pmic_bxtwc.c
+++ b/drivers/mfd/intel_soc_pmic_bxtwc.c
@@ -42,6 +42,7 @@
#define BXTWC_GPIOIRQ0 0x4E0B
#define BXTWC_GPIOIRQ1 0x4E0C
#define BXTWC_CRITIRQ 0x4E0D
+#define BXTWC_TMUIRQ 0x4FB6
/* Interrupt MASK Registers */
#define BXTWC_MIRQLVL1 0x4E0E
@@ -59,6 +60,7 @@
#define BXTWC_MGPIO0IRQ 0x4E19
#define BXTWC_MGPIO1IRQ 0x4E1A
#define BXTWC_MCRITIRQ 0x4E1B
+#define BXTWC_MTMUIRQ 0x4FB7
/* Whiskey Cove PMIC share same ACPI ID between different platforms */
#define BROXTON_PMIC_WC_HRV 4
@@ -92,6 +94,7 @@ enum bxtwc_irqs_level2 {
BXTWC_GPIO0_IRQ,
BXTWC_GPIO1_IRQ,
BXTWC_CRIT_IRQ,
+ BXTWC_TMU_IRQ,
};
static const struct regmap_irq bxtwc_regmap_irqs[] = {
@@ -120,6 +123,10 @@ static const struct regmap_irq bxtwc_regmap_irqs_level2[] = {
REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 9, 0x03),
};
+static const struct regmap_irq bxtwc_regmap_irqs_tmu[] = {
+ REGMAP_IRQ_REG(BXTWC_TMU_IRQ, 0, 0x06),
+};
+
static struct regmap_irq_chip bxtwc_regmap_irq_chip = {
.name = "bxtwc_irq_chip",
.status_base = BXTWC_IRQLVL1,
@@ -138,6 +145,15 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip_level2 = {
.num_regs = 10,
};
+static struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = {
+ .name = "bxtwc_irq_chip_tmu",
+ .status_base = BXTWC_TMUIRQ,
+ .mask_base = BXTWC_MTMUIRQ,
+ .irqs = bxtwc_regmap_irqs_tmu,
+ .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_tmu),
+ .num_regs = 1,
+};
+
static struct resource gpio_resources[] = {
DEFINE_RES_IRQ_NAMED(BXTWC_GPIO0_IRQ, "GPIO0"),
DEFINE_RES_IRQ_NAMED(BXTWC_GPIO1_IRQ, "GPIO1"),
@@ -166,6 +182,10 @@ static struct resource bcu_resources[] = {
DEFINE_RES_IRQ_NAMED(BXTWC_BCU_IRQ, "BCU"),
};
+static struct resource tmu_resources[] = {
+ DEFINE_RES_IRQ_NAMED(BXTWC_TMU_IRQ, "TMU"),
+};
+
static struct mfd_cell bxt_wc_dev[] = {
{
.name = "bxt_wcove_gpadc",
@@ -193,6 +213,12 @@ static struct mfd_cell bxt_wc_dev[] = {
.resources = bcu_resources,
},
{
+ .name = "bxt_wcove_tmu",
+ .num_resources = ARRAY_SIZE(tmu_resources),
+ .resources = tmu_resources,
+ },
+
+ {
.name = "bxt_wcove_gpio",
.num_resources = ARRAY_SIZE(gpio_resources),
.resources = gpio_resources,
@@ -402,6 +428,15 @@ static int bxtwc_probe(struct platform_device *pdev)
goto err_irq_chip_level2;
}
+ ret = regmap_add_irq_chip(pmic->regmap, pmic->irq,
+ IRQF_ONESHOT | IRQF_SHARED,
+ 0, &bxtwc_regmap_irq_chip_tmu,
+ &pmic->irq_chip_data_tmu);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add TMU IRQ chip\n");
+ goto err_irq_chip_tmu;
+ }
+
ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, bxt_wc_dev,
ARRAY_SIZE(bxt_wc_dev), NULL, 0,
NULL);
@@ -431,6 +466,8 @@ static int bxtwc_probe(struct platform_device *pdev)
err_sysfs:
mfd_remove_devices(&pdev->dev);
err_mfd:
+ regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_tmu);
+err_irq_chip_tmu:
regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2);
err_irq_chip_level2:
regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data);
@@ -446,6 +483,7 @@ static int bxtwc_remove(struct platform_device *pdev)
mfd_remove_devices(&pdev->dev);
regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data);
regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2);
+ regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_tmu);
return 0;
}
@@ -481,7 +519,7 @@ static const struct acpi_device_id bxtwc_acpi_ids[] = {
{ "INT34D3", },
{ }
};
-MODULE_DEVICE_TABLE(acpi, pmic_acpi_ids);
+MODULE_DEVICE_TABLE(acpi, bxtwc_acpi_ids);
static struct platform_driver bxtwc_driver = {
.probe = bxtwc_probe,
diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c
index c8dee47b45d9..1ef7575547e6 100644
--- a/drivers/mfd/lpc_ich.c
+++ b/drivers/mfd/lpc_ich.c
@@ -493,6 +493,7 @@ static struct lpc_ich_info lpc_chipset_info[] = {
[LPC_LPT] = {
.name = "Lynx Point",
.iTCO_version = 2,
+ .gpio_version = ICH_V5_GPIO,
},
[LPC_LPT_LP] = {
.name = "Lynx Point_LP",
@@ -530,6 +531,7 @@ static struct lpc_ich_info lpc_chipset_info[] = {
[LPC_9S] = {
.name = "9 Series",
.iTCO_version = 2,
+ .gpio_version = ICH_V5_GPIO,
},
};
diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c
index 8f8bacb67a15..ee9e9ea10444 100644
--- a/drivers/mfd/palmas.c
+++ b/drivers/mfd/palmas.c
@@ -431,9 +431,6 @@ static void palmas_power_off(void)
unsigned int addr;
int ret, slave;
- if (!palmas_dev)
- return;
-
slave = PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE);
addr = PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE, PALMAS_DEV_CTRL);
diff --git a/drivers/mfd/qcom-pm8xxx.c b/drivers/mfd/qcom-pm8xxx.c
index 7f9620ec61e8..f08758f6b418 100644
--- a/drivers/mfd/qcom-pm8xxx.c
+++ b/drivers/mfd/qcom-pm8xxx.c
@@ -39,6 +39,20 @@
#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 PM8821_SSBI_REG_ADDR_IRQ_BASE 0x100
+#define PM8821_SSBI_REG_ADDR_IRQ_MASTER0 (PM8821_SSBI_REG_ADDR_IRQ_BASE + 0x30)
+#define PM8821_SSBI_REG_ADDR_IRQ_MASTER1 (PM8821_SSBI_REG_ADDR_IRQ_BASE + 0xb0)
+#define PM8821_SSBI_REG(m, b, offset) \
+ ((m == 0) ? \
+ (PM8821_SSBI_REG_ADDR_IRQ_MASTER0 + b + offset) : \
+ (PM8821_SSBI_REG_ADDR_IRQ_MASTER1 + b + offset))
+#define PM8821_SSBI_ADDR_IRQ_ROOT(m, b) PM8821_SSBI_REG(m, b, 0x0)
+#define PM8821_SSBI_ADDR_IRQ_CLEAR(m, b) PM8821_SSBI_REG(m, b, 0x01)
+#define PM8821_SSBI_ADDR_IRQ_MASK(m, b) PM8821_SSBI_REG(m, b, 0x08)
+#define PM8821_SSBI_ADDR_IRQ_RT_STATUS(m, b) PM8821_SSBI_REG(m, b, 0x0f)
+
+#define PM8821_BLOCKS_PER_MASTER 7
+
#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 */
@@ -54,6 +68,7 @@
#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */
#define PM8XXX_NR_IRQS 256
+#define PM8821_NR_IRQS 112
struct pm_irq_chip {
struct regmap *regmap;
@@ -65,6 +80,12 @@ struct pm_irq_chip {
u8 config[0];
};
+struct pm_irq_data {
+ int num_irqs;
+ const struct irq_domain_ops *irq_domain_ops;
+ void (*irq_handler)(struct irq_desc *desc);
+};
+
static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp,
unsigned int *ip)
{
@@ -182,6 +203,78 @@ static void pm8xxx_irq_handler(struct irq_desc *desc)
chained_irq_exit(irq_chip, desc);
}
+static void pm8821_irq_block_handler(struct pm_irq_chip *chip,
+ int master, int block)
+{
+ int pmirq, irq, i, ret;
+ unsigned int bits;
+
+ ret = regmap_read(chip->regmap,
+ PM8821_SSBI_ADDR_IRQ_ROOT(master, block), &bits);
+ if (ret) {
+ pr_err("Reading block %d failed ret=%d", block, ret);
+ return;
+ }
+
+ /* Convert block offset to global block number */
+ block += (master * PM8821_BLOCKS_PER_MASTER) - 1;
+
+ /* Check IRQ bits */
+ for (i = 0; i < 8; i++) {
+ if (bits & BIT(i)) {
+ pmirq = block * 8 + i;
+ irq = irq_find_mapping(chip->irqdomain, pmirq);
+ generic_handle_irq(irq);
+ }
+ }
+}
+
+static inline void pm8821_irq_master_handler(struct pm_irq_chip *chip,
+ int master, u8 master_val)
+{
+ int block;
+
+ for (block = 1; block < 8; block++)
+ if (master_val & BIT(block))
+ pm8821_irq_block_handler(chip, master, block);
+}
+
+static void pm8821_irq_handler(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 master;
+ int ret;
+
+ chained_irq_enter(irq_chip, desc);
+ ret = regmap_read(chip->regmap,
+ PM8821_SSBI_REG_ADDR_IRQ_MASTER0, &master);
+ if (ret) {
+ pr_err("Failed to read master 0 ret=%d\n", ret);
+ goto done;
+ }
+
+ /* bits 1 through 7 marks the first 7 blocks in master 0 */
+ if (master & GENMASK(7, 1))
+ pm8821_irq_master_handler(chip, 0, master);
+
+ /* bit 0 marks if master 1 contains any bits */
+ if (!(master & BIT(0)))
+ goto done;
+
+ ret = regmap_read(chip->regmap,
+ PM8821_SSBI_REG_ADDR_IRQ_MASTER1, &master);
+ if (ret) {
+ pr_err("Failed to read master 1 ret=%d\n", ret);
+ goto done;
+ }
+
+ pm8821_irq_master_handler(chip, 1, master);
+
+done:
+ 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);
@@ -299,6 +392,104 @@ static const struct irq_domain_ops pm8xxx_irq_domain_ops = {
.map = pm8xxx_irq_domain_map,
};
+static void pm8821_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);
+ u8 block, master;
+ int irq_bit, rc;
+
+ block = pmirq / 8;
+ master = block / PM8821_BLOCKS_PER_MASTER;
+ irq_bit = pmirq % 8;
+ block %= PM8821_BLOCKS_PER_MASTER;
+
+ rc = regmap_update_bits(chip->regmap,
+ PM8821_SSBI_ADDR_IRQ_MASK(master, block),
+ BIT(irq_bit), BIT(irq_bit));
+ if (rc) {
+ pr_err("Failed to mask IRQ:%d rc=%d\n", pmirq, rc);
+ return;
+ }
+
+ rc = regmap_update_bits(chip->regmap,
+ PM8821_SSBI_ADDR_IRQ_CLEAR(master, block),
+ BIT(irq_bit), BIT(irq_bit));
+ if (rc)
+ pr_err("Failed to CLEAR IRQ:%d rc=%d\n", pmirq, rc);
+}
+
+static void pm8821_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, rc;
+ u8 block, master;
+
+ block = pmirq / 8;
+ master = block / PM8821_BLOCKS_PER_MASTER;
+ irq_bit = pmirq % 8;
+ block %= PM8821_BLOCKS_PER_MASTER;
+
+ rc = regmap_update_bits(chip->regmap,
+ PM8821_SSBI_ADDR_IRQ_MASK(master, block),
+ BIT(irq_bit), ~BIT(irq_bit));
+ if (rc)
+ pr_err("Failed to read/write unmask IRQ:%d rc=%d\n", pmirq, rc);
+
+}
+
+static int pm8821_irq_get_irqchip_state(struct irq_data *d,
+ enum irqchip_irq_state which,
+ bool *state)
+{
+ struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+ int rc, pmirq = irqd_to_hwirq(d);
+ u8 block, irq_bit, master;
+ unsigned int bits;
+
+ block = pmirq / 8;
+ master = block / PM8821_BLOCKS_PER_MASTER;
+ irq_bit = pmirq % 8;
+ block %= PM8821_BLOCKS_PER_MASTER;
+
+ rc = regmap_read(chip->regmap,
+ PM8821_SSBI_ADDR_IRQ_RT_STATUS(master, block), &bits);
+ if (rc) {
+ pr_err("Reading Status of IRQ %d failed rc=%d\n", pmirq, rc);
+ return rc;
+ }
+
+ *state = !!(bits & BIT(irq_bit));
+
+ return rc;
+}
+
+static struct irq_chip pm8821_irq_chip = {
+ .name = "pm8821",
+ .irq_mask_ack = pm8821_irq_mask_ack,
+ .irq_unmask = pm8821_irq_unmask,
+ .irq_get_irqchip_state = pm8821_irq_get_irqchip_state,
+ .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
+};
+
+static int pm8821_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, &pm8821_irq_chip, handle_level_irq);
+ irq_set_chip_data(irq, chip);
+ irq_set_noprobe(irq);
+
+ return 0;
+}
+
+static const struct irq_domain_ops pm8821_irq_domain_ops = {
+ .xlate = irq_domain_xlate_twocell,
+ .map = pm8821_irq_domain_map,
+};
+
static const struct regmap_config ssbi_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
@@ -308,22 +499,41 @@ static const struct regmap_config ssbi_regmap_config = {
.reg_write = ssbi_reg_write
};
+static const struct pm_irq_data pm8xxx_data = {
+ .num_irqs = PM8XXX_NR_IRQS,
+ .irq_domain_ops = &pm8xxx_irq_domain_ops,
+ .irq_handler = pm8xxx_irq_handler,
+};
+
+static const struct pm_irq_data pm8821_data = {
+ .num_irqs = PM8821_NR_IRQS,
+ .irq_domain_ops = &pm8821_irq_domain_ops,
+ .irq_handler = pm8821_irq_handler,
+};
+
static const struct of_device_id pm8xxx_id_table[] = {
- { .compatible = "qcom,pm8018", },
- { .compatible = "qcom,pm8058", },
- { .compatible = "qcom,pm8921", },
+ { .compatible = "qcom,pm8018", .data = &pm8xxx_data},
+ { .compatible = "qcom,pm8058", .data = &pm8xxx_data},
+ { .compatible = "qcom,pm8821", .data = &pm8821_data},
+ { .compatible = "qcom,pm8921", .data = &pm8xxx_data},
{ }
};
MODULE_DEVICE_TABLE(of, pm8xxx_id_table);
static int pm8xxx_probe(struct platform_device *pdev)
{
+ const struct pm_irq_data *data;
struct regmap *regmap;
int irq, rc;
unsigned int val;
u32 rev;
struct pm_irq_chip *chip;
- unsigned int nirqs = PM8XXX_NR_IRQS;
+
+ data = of_device_get_match_data(&pdev->dev);
+ if (!data) {
+ dev_err(&pdev->dev, "No matching driver data found\n");
+ return -EINVAL;
+ }
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@@ -354,25 +564,26 @@ static int pm8xxx_probe(struct platform_device *pdev)
rev |= val << BITS_PER_BYTE;
chip = devm_kzalloc(&pdev->dev, sizeof(*chip) +
- sizeof(chip->config[0]) * nirqs,
- GFP_KERNEL);
+ sizeof(chip->config[0]) * data->num_irqs,
+ GFP_KERNEL);
if (!chip)
return -ENOMEM;
platform_set_drvdata(pdev, chip);
chip->regmap = regmap;
- chip->num_irqs = nirqs;
+ chip->num_irqs = data->num_irqs;
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->irqdomain = irq_domain_add_linear(pdev->dev.of_node,
+ data->num_irqs,
+ data->irq_domain_ops,
chip);
if (!chip->irqdomain)
return -ENODEV;
- irq_set_chained_handler_and_data(irq, pm8xxx_irq_handler, chip);
+ irq_set_chained_handler_and_data(irq, data->irq_handler, chip);
irq_set_irq_wake(irq, 1);
rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
index 0f8acc5882a4..2c9acdba7c2d 100644
--- a/drivers/mfd/rk808.c
+++ b/drivers/mfd/rk808.c
@@ -290,6 +290,24 @@ static void rk808_device_shutdown(void)
dev_err(&rk808_i2c_client->dev, "power off error!\n");
}
+static void rk818_device_shutdown(void)
+{
+ int ret;
+ struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
+
+ if (!rk808) {
+ dev_warn(&rk808_i2c_client->dev,
+ "have no rk818, so do nothing here\n");
+ return;
+ }
+
+ ret = regmap_update_bits(rk808->regmap,
+ RK818_DEVCTRL_REG,
+ DEV_OFF, DEV_OFF);
+ if (ret)
+ dev_err(&rk808_i2c_client->dev, "power off error!\n");
+}
+
static const struct of_device_id rk808_of_match[] = {
{ .compatible = "rockchip,rk808" },
{ .compatible = "rockchip,rk818" },
@@ -304,6 +322,7 @@ static int rk808_probe(struct i2c_client *client,
struct rk808 *rk808;
const struct rk808_reg_data *pre_init_reg;
const struct mfd_cell *cells;
+ void (*pm_pwroff_fn)(void);
int nr_pre_init_regs;
int nr_cells;
int pm_off = 0;
@@ -331,6 +350,7 @@ static int rk808_probe(struct i2c_client *client,
nr_pre_init_regs = ARRAY_SIZE(rk808_pre_init_reg);
cells = rk808s;
nr_cells = ARRAY_SIZE(rk808s);
+ pm_pwroff_fn = rk808_device_shutdown;
break;
case RK818_ID:
rk808->regmap_cfg = &rk818_regmap_config;
@@ -339,6 +359,7 @@ static int rk808_probe(struct i2c_client *client,
nr_pre_init_regs = ARRAY_SIZE(rk818_pre_init_reg);
cells = rk818s;
nr_cells = ARRAY_SIZE(rk818s);
+ pm_pwroff_fn = rk818_device_shutdown;
break;
default:
dev_err(&client->dev, "Unsupported RK8XX ID %lu\n",
@@ -393,7 +414,7 @@ static int rk808_probe(struct i2c_client *client,
"rockchip,system-power-controller");
if (pm_off && !pm_power_off) {
rk808_i2c_client = client;
- pm_power_off = rk808_device_shutdown;
+ pm_power_off = pm_pwroff_fn;
}
return 0;
diff --git a/drivers/mfd/rn5t618.c b/drivers/mfd/rn5t618.c
index ee94080e1cbb..8131d1975745 100644
--- a/drivers/mfd/rn5t618.c
+++ b/drivers/mfd/rn5t618.c
@@ -87,6 +87,7 @@ static int rn5t618_restart(struct notifier_block *this,
static const struct of_device_id rn5t618_of_match[] = {
{ .compatible = "ricoh,rn5t567", .data = (void *)RN5T567 },
{ .compatible = "ricoh,rn5t618", .data = (void *)RN5T618 },
+ { .compatible = "ricoh,rc5t619", .data = (void *)RC5T619 },
{ }
};
MODULE_DEVICE_TABLE(of, rn5t618_of_match);
diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c
index c180b7533bba..e6a3d999a376 100644
--- a/drivers/mfd/si476x-i2c.c
+++ b/drivers/mfd/si476x-i2c.c
@@ -753,7 +753,7 @@ static int si476x_core_probe(struct i2c_client *client,
ARRAY_SIZE(core->supplies),
core->supplies);
if (rval) {
- dev_err(&client->dev, "Failet to gett all of the regulators\n");
+ dev_err(&client->dev, "Failed to get all of the regulators\n");
goto free_gpio;
}
diff --git a/drivers/mfd/sun4i-gpadc.c b/drivers/mfd/sun4i-gpadc.c
new file mode 100644
index 000000000000..9cfc88134d03
--- /dev/null
+++ b/drivers/mfd/sun4i-gpadc.c
@@ -0,0 +1,181 @@
+/* ADC MFD core driver for sunxi platforms
+ *
+ * Copyright (c) 2016 Quentin Schulz <quentin.schulz@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/sun4i-gpadc.h>
+
+#define ARCH_SUN4I_A10 0
+#define ARCH_SUN5I_A13 1
+#define ARCH_SUN6I_A31 2
+
+static struct resource adc_resources[] = {
+ DEFINE_RES_IRQ_NAMED(SUN4I_GPADC_IRQ_FIFO_DATA, "FIFO_DATA_PENDING"),
+ DEFINE_RES_IRQ_NAMED(SUN4I_GPADC_IRQ_TEMP_DATA, "TEMP_DATA_PENDING"),
+};
+
+static const struct regmap_irq sun4i_gpadc_regmap_irq[] = {
+ REGMAP_IRQ_REG(SUN4I_GPADC_IRQ_FIFO_DATA, 0,
+ SUN4I_GPADC_INT_FIFOC_TP_DATA_IRQ_EN),
+ REGMAP_IRQ_REG(SUN4I_GPADC_IRQ_TEMP_DATA, 0,
+ SUN4I_GPADC_INT_FIFOC_TEMP_IRQ_EN),
+};
+
+static const struct regmap_irq_chip sun4i_gpadc_regmap_irq_chip = {
+ .name = "sun4i_gpadc_irq_chip",
+ .status_base = SUN4I_GPADC_INT_FIFOS,
+ .ack_base = SUN4I_GPADC_INT_FIFOS,
+ .mask_base = SUN4I_GPADC_INT_FIFOC,
+ .init_ack_masked = true,
+ .mask_invert = true,
+ .irqs = sun4i_gpadc_regmap_irq,
+ .num_irqs = ARRAY_SIZE(sun4i_gpadc_regmap_irq),
+ .num_regs = 1,
+};
+
+static struct mfd_cell sun4i_gpadc_cells[] = {
+ {
+ .name = "sun4i-a10-gpadc-iio",
+ .resources = adc_resources,
+ .num_resources = ARRAY_SIZE(adc_resources),
+ },
+ { .name = "iio_hwmon" }
+};
+
+static struct mfd_cell sun5i_gpadc_cells[] = {
+ {
+ .name = "sun5i-a13-gpadc-iio",
+ .resources = adc_resources,
+ .num_resources = ARRAY_SIZE(adc_resources),
+ },
+ { .name = "iio_hwmon" },
+};
+
+static struct mfd_cell sun6i_gpadc_cells[] = {
+ {
+ .name = "sun6i-a31-gpadc-iio",
+ .resources = adc_resources,
+ .num_resources = ARRAY_SIZE(adc_resources),
+ },
+ { .name = "iio_hwmon" },
+};
+
+static const struct regmap_config sun4i_gpadc_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .fast_io = true,
+};
+
+static const struct of_device_id sun4i_gpadc_of_match[] = {
+ {
+ .compatible = "allwinner,sun4i-a10-ts",
+ .data = (void *)ARCH_SUN4I_A10,
+ }, {
+ .compatible = "allwinner,sun5i-a13-ts",
+ .data = (void *)ARCH_SUN5I_A13,
+ }, {
+ .compatible = "allwinner,sun6i-a31-ts",
+ .data = (void *)ARCH_SUN6I_A31,
+ }, { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, sun4i_gpadc_of_match);
+
+static int sun4i_gpadc_probe(struct platform_device *pdev)
+{
+ struct sun4i_gpadc_dev *dev;
+ struct resource *mem;
+ const struct of_device_id *of_id;
+ const struct mfd_cell *cells;
+ unsigned int irq, size;
+ int ret;
+
+ of_id = of_match_node(sun4i_gpadc_of_match, pdev->dev.of_node);
+ if (!of_id)
+ return -EINVAL;
+
+ switch ((long)of_id->data) {
+ case ARCH_SUN4I_A10:
+ cells = sun4i_gpadc_cells;
+ size = ARRAY_SIZE(sun4i_gpadc_cells);
+ break;
+ case ARCH_SUN5I_A13:
+ cells = sun5i_gpadc_cells;
+ size = ARRAY_SIZE(sun5i_gpadc_cells);
+ break;
+ case ARCH_SUN6I_A31:
+ cells = sun6i_gpadc_cells;
+ size = ARRAY_SIZE(sun6i_gpadc_cells);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dev->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(dev->base))
+ return PTR_ERR(dev->base);
+
+ dev->dev = &pdev->dev;
+ dev_set_drvdata(dev->dev, dev);
+
+ dev->regmap = devm_regmap_init_mmio(dev->dev, dev->base,
+ &sun4i_gpadc_regmap_config);
+ if (IS_ERR(dev->regmap)) {
+ ret = PTR_ERR(dev->regmap);
+ dev_err(&pdev->dev, "failed to init regmap: %d\n", ret);
+ return ret;
+ }
+
+ /* Disable all interrupts */
+ regmap_write(dev->regmap, SUN4I_GPADC_INT_FIFOC, 0);
+
+ irq = platform_get_irq(pdev, 0);
+ ret = devm_regmap_add_irq_chip(&pdev->dev, dev->regmap, irq,
+ IRQF_ONESHOT, 0,
+ &sun4i_gpadc_regmap_irq_chip,
+ &dev->regmap_irqc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add irq chip: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_mfd_add_devices(dev->dev, 0, cells, size, NULL, 0, NULL);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add MFD devices: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct platform_driver sun4i_gpadc_driver = {
+ .driver = {
+ .name = "sun4i-gpadc",
+ .of_match_table = of_match_ptr(sun4i_gpadc_of_match),
+ },
+ .probe = sun4i_gpadc_probe,
+};
+
+module_platform_driver(sun4i_gpadc_driver);
+
+MODULE_DESCRIPTION("Allwinner sunxi platforms' GPADC MFD core driver");
+MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c
index 274bf39968aa..cc9e563f23aa 100644
--- a/drivers/mfd/tc3589x.c
+++ b/drivers/mfd/tc3589x.c
@@ -53,7 +53,7 @@ int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg)
EXPORT_SYMBOL_GPL(tc3589x_reg_read);
/**
- * tc3589x_reg_read() - write a single TC3589x register
+ * tc3589x_reg_write() - write a single TC3589x register
* @tc3589x: Device to write to
* @reg: Register to read
* @data: Value to write
@@ -118,7 +118,7 @@ EXPORT_SYMBOL_GPL(tc3589x_block_write);
* @tc3589x: Device to write to
* @reg: Register to write
* @mask: Mask of bits to set
- * @values: Value to set
+ * @val: Value to set
*/
int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val)
{
diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c
index 9a4d8684dd32..f769c7d4e335 100644
--- a/drivers/mfd/tps65217.c
+++ b/drivers/mfd/tps65217.c
@@ -42,26 +42,6 @@ static struct resource pb_resources[] = {
DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_PB, "PB"),
};
-struct tps65217_irq {
- int mask;
- int interrupt;
-};
-
-static const struct tps65217_irq tps65217_irqs[] = {
- [TPS65217_IRQ_PB] = {
- .mask = TPS65217_INT_PBM,
- .interrupt = TPS65217_INT_PBI,
- },
- [TPS65217_IRQ_AC] = {
- .mask = TPS65217_INT_ACM,
- .interrupt = TPS65217_INT_ACI,
- },
- [TPS65217_IRQ_USB] = {
- .mask = TPS65217_INT_USBM,
- .interrupt = TPS65217_INT_USBI,
- },
-};
-
static void tps65217_irq_lock(struct irq_data *data)
{
struct tps65217 *tps = irq_data_get_irq_chip_data(data);
@@ -74,37 +54,32 @@ static void tps65217_irq_sync_unlock(struct irq_data *data)
struct tps65217 *tps = irq_data_get_irq_chip_data(data);
int ret;
- ret = tps65217_reg_write(tps, TPS65217_REG_INT, tps->irq_mask,
- TPS65217_PROTECT_NONE);
+ ret = tps65217_set_bits(tps, TPS65217_REG_INT, TPS65217_INT_MASK,
+ tps->irq_mask, TPS65217_PROTECT_NONE);
if (ret != 0)
dev_err(tps->dev, "Failed to sync IRQ masks\n");
mutex_unlock(&tps->irq_lock);
}
-static inline const struct tps65217_irq *
-irq_to_tps65217_irq(struct tps65217 *tps, struct irq_data *data)
-{
- return &tps65217_irqs[data->hwirq];
-}
-
static void tps65217_irq_enable(struct irq_data *data)
{
struct tps65217 *tps = irq_data_get_irq_chip_data(data);
- const struct tps65217_irq *irq_data = irq_to_tps65217_irq(tps, data);
+ u8 mask = BIT(data->hwirq) << TPS65217_INT_SHIFT;
- tps->irq_mask &= ~irq_data->mask;
+ tps->irq_mask &= ~mask;
}
static void tps65217_irq_disable(struct irq_data *data)
{
struct tps65217 *tps = irq_data_get_irq_chip_data(data);
- const struct tps65217_irq *irq_data = irq_to_tps65217_irq(tps, data);
+ u8 mask = BIT(data->hwirq) << TPS65217_INT_SHIFT;
- tps->irq_mask |= irq_data->mask;
+ tps->irq_mask |= mask;
}
static struct irq_chip tps65217_irq_chip = {
+ .name = "tps65217",
.irq_bus_lock = tps65217_irq_lock,
.irq_bus_sync_unlock = tps65217_irq_sync_unlock,
.irq_enable = tps65217_irq_enable,
@@ -149,8 +124,8 @@ static irqreturn_t tps65217_irq_thread(int irq, void *data)
return IRQ_NONE;
}
- for (i = 0; i < ARRAY_SIZE(tps65217_irqs); i++) {
- if (status & tps65217_irqs[i].interrupt) {
+ for (i = 0; i < TPS65217_NUM_IRQ; i++) {
+ if (status & BIT(i)) {
handle_nested_irq(irq_find_mapping(tps->irq_domain, i));
handled = true;
}
@@ -188,10 +163,9 @@ static int tps65217_irq_init(struct tps65217 *tps, int irq)
tps->irq = irq;
/* Mask all interrupt sources */
- tps->irq_mask = (TPS65217_INT_RESERVEDM | TPS65217_INT_PBM
- | TPS65217_INT_ACM | TPS65217_INT_USBM);
- tps65217_reg_write(tps, TPS65217_REG_INT, tps->irq_mask,
- TPS65217_PROTECT_NONE);
+ tps->irq_mask = TPS65217_INT_MASK;
+ tps65217_set_bits(tps, TPS65217_REG_INT, TPS65217_INT_MASK,
+ TPS65217_INT_MASK, TPS65217_PROTECT_NONE);
tps->irq_domain = irq_domain_add_linear(tps->dev->of_node,
TPS65217_NUM_IRQ, &tps65217_irq_domain_ops, tps);
@@ -209,6 +183,8 @@ static int tps65217_irq_init(struct tps65217 *tps, int irq)
return ret;
}
+ enable_irq_wake(irq);
+
return 0;
}
@@ -424,6 +400,24 @@ static int tps65217_probe(struct i2c_client *client,
return 0;
}
+static int tps65217_remove(struct i2c_client *client)
+{
+ struct tps65217 *tps = i2c_get_clientdata(client);
+ unsigned int virq;
+ int i;
+
+ for (i = 0; i < TPS65217_NUM_IRQ; i++) {
+ virq = irq_find_mapping(tps->irq_domain, i);
+ if (virq)
+ irq_dispose_mapping(virq);
+ }
+
+ irq_domain_remove(tps->irq_domain);
+ tps->irq_domain = NULL;
+
+ return 0;
+}
+
static const struct i2c_device_id tps65217_id_table[] = {
{"tps65217", TPS65217},
{ /* sentinel */ }
@@ -437,6 +431,7 @@ static struct i2c_driver tps65217_driver = {
},
.id_table = tps65217_id_table,
.probe = tps65217_probe,
+ .remove = tps65217_remove,
};
static int __init tps65217_init(void)
diff --git a/drivers/mfd/tps65218.c b/drivers/mfd/tps65218.c
index ba610adbdbff..13834a0d2817 100644
--- a/drivers/mfd/tps65218.c
+++ b/drivers/mfd/tps65218.c
@@ -33,19 +33,17 @@
#define TPS65218_PASSWORD_REGS_UNLOCK 0x7D
-/**
- * tps65218_reg_read: Read a single tps65218 register.
- *
- * @tps: Device to read from.
- * @reg: Register to read.
- * @val: Contians the value
- */
-int tps65218_reg_read(struct tps65218 *tps, unsigned int reg,
- unsigned int *val)
-{
- return regmap_read(tps->regmap, reg, val);
-}
-EXPORT_SYMBOL_GPL(tps65218_reg_read);
+static const struct mfd_cell tps65218_cells[] = {
+ {
+ .name = "tps65218-pwrbutton",
+ .of_compatible = "ti,tps65218-pwrbutton",
+ },
+ {
+ .name = "tps65218-gpio",
+ .of_compatible = "ti,tps65218-gpio",
+ },
+ { .name = "tps65218-regulator", },
+};
/**
* tps65218_reg_write: Write a single tps65218 register.
@@ -93,7 +91,7 @@ static int tps65218_update_bits(struct tps65218 *tps, unsigned int reg,
int ret;
unsigned int data;
- ret = tps65218_reg_read(tps, reg, &data);
+ ret = regmap_read(tps->regmap, reg, &data);
if (ret) {
dev_err(tps->dev, "Read from reg 0x%x failed\n", reg);
return ret;
@@ -251,7 +249,7 @@ static int tps65218_probe(struct i2c_client *client,
if (ret < 0)
return ret;
- ret = tps65218_reg_read(tps, TPS65218_REG_CHIPID, &chipid);
+ ret = regmap_read(tps->regmap, TPS65218_REG_CHIPID, &chipid);
if (ret) {
dev_err(tps->dev, "Failed to read chipid: %d\n", ret);
return ret;
@@ -259,8 +257,10 @@ static int tps65218_probe(struct i2c_client *client,
tps->rev = chipid & TPS65218_CHIPID_REV_MASK;
- ret = of_platform_populate(client->dev.of_node, NULL, NULL,
- &client->dev);
+ ret = mfd_add_devices(tps->dev, PLATFORM_DEVID_AUTO, tps65218_cells,
+ ARRAY_SIZE(tps65218_cells), NULL, 0,
+ regmap_irq_get_domain(tps->irq_data));
+
if (ret < 0)
goto err_irq;
diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c
index a88cfa80dbc4..f33567bc428d 100644
--- a/drivers/mfd/tps65912-core.c
+++ b/drivers/mfd/tps65912-core.c
@@ -77,6 +77,23 @@ static struct regmap_irq_chip tps65912_irq_chip = {
.init_ack_masked = true,
};
+static const struct regmap_range tps65912_yes_ranges[] = {
+ regmap_reg_range(TPS65912_INT_STS, TPS65912_GPIO5),
+};
+
+static const struct regmap_access_table tps65912_volatile_table = {
+ .yes_ranges = tps65912_yes_ranges,
+ .n_yes_ranges = ARRAY_SIZE(tps65912_yes_ranges),
+};
+
+const struct regmap_config tps65912_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_RBTREE,
+ .volatile_table = &tps65912_volatile_table,
+};
+EXPORT_SYMBOL_GPL(tps65912_regmap_config);
+
int tps65912_device_init(struct tps65912 *tps)
{
int ret;
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c
index ab8b23b5bd22..853113d97c1e 100644
--- a/drivers/mfd/wm5102-tables.c
+++ b/drivers/mfd/wm5102-tables.c
@@ -244,752 +244,752 @@ const struct regmap_irq_chip wm5102_irq = {
};
static const struct reg_default wm5102_reg_default[] = {
- { 0x00000008, 0x0019 }, /* R8 - Ctrl IF SPI CFG 1 */
- { 0x00000009, 0x0001 }, /* R9 - Ctrl IF I2C1 CFG 1 */
- { 0x00000020, 0x0000 }, /* R32 - Tone Generator 1 */
- { 0x00000021, 0x1000 }, /* R33 - Tone Generator 2 */
- { 0x00000022, 0x0000 }, /* R34 - Tone Generator 3 */
- { 0x00000023, 0x1000 }, /* R35 - Tone Generator 4 */
- { 0x00000024, 0x0000 }, /* R36 - Tone Generator 5 */
- { 0x00000030, 0x0000 }, /* R48 - PWM Drive 1 */
- { 0x00000031, 0x0100 }, /* R49 - PWM Drive 2 */
- { 0x00000032, 0x0100 }, /* R50 - PWM Drive 3 */
- { 0x00000040, 0x0000 }, /* R64 - Wake control */
- { 0x00000041, 0x0000 }, /* R65 - Sequence control */
- { 0x00000061, 0x01FF }, /* R97 - Sample Rate Sequence Select 1 */
- { 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */
- { 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */
- { 0x00000064, 0x01FF }, /* R100 - Sample Rate Sequence Select 4 */
+ { 0x00000008, 0x0019 }, /* R8 - Ctrl IF SPI CFG 1 */
+ { 0x00000009, 0x0001 }, /* R9 - Ctrl IF I2C1 CFG 1 */
+ { 0x00000020, 0x0000 }, /* R32 - Tone Generator 1 */
+ { 0x00000021, 0x1000 }, /* R33 - Tone Generator 2 */
+ { 0x00000022, 0x0000 }, /* R34 - Tone Generator 3 */
+ { 0x00000023, 0x1000 }, /* R35 - Tone Generator 4 */
+ { 0x00000024, 0x0000 }, /* R36 - Tone Generator 5 */
+ { 0x00000030, 0x0000 }, /* R48 - PWM Drive 1 */
+ { 0x00000031, 0x0100 }, /* R49 - PWM Drive 2 */
+ { 0x00000032, 0x0100 }, /* R50 - PWM Drive 3 */
+ { 0x00000040, 0x0000 }, /* R64 - Wake control */
+ { 0x00000041, 0x0000 }, /* R65 - Sequence control */
+ { 0x00000061, 0x01FF }, /* R97 - Sample Rate Sequence Select 1 */
+ { 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */
+ { 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */
+ { 0x00000064, 0x01FF }, /* R100 - Sample Rate Sequence Select 4 */
{ 0x00000066, 0x01FF }, /* R102 - Always On Triggers Sequence Select 1 */
{ 0x00000067, 0x01FF }, /* R103 - Always On Triggers Sequence Select 2 */
{ 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 3 */
{ 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 4 */
{ 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 5 */
{ 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 6 */
- { 0x00000070, 0x0000 }, /* R112 - Comfort Noise Generator */
- { 0x00000090, 0x0000 }, /* R144 - Haptics Control 1 */
- { 0x00000091, 0x7FFF }, /* R145 - Haptics Control 2 */
- { 0x00000092, 0x0000 }, /* R146 - Haptics phase 1 intensity */
- { 0x00000093, 0x0000 }, /* R147 - Haptics phase 1 duration */
- { 0x00000094, 0x0000 }, /* R148 - Haptics phase 2 intensity */
- { 0x00000095, 0x0000 }, /* R149 - Haptics phase 2 duration */
- { 0x00000096, 0x0000 }, /* R150 - Haptics phase 3 intensity */
- { 0x00000097, 0x0000 }, /* R151 - Haptics phase 3 duration */
+ { 0x00000070, 0x0000 }, /* R112 - Comfort Noise Generator */
+ { 0x00000090, 0x0000 }, /* R144 - Haptics Control 1 */
+ { 0x00000091, 0x7FFF }, /* R145 - Haptics Control 2 */
+ { 0x00000092, 0x0000 }, /* R146 - Haptics phase 1 intensity */
+ { 0x00000093, 0x0000 }, /* R147 - Haptics phase 1 duration */
+ { 0x00000094, 0x0000 }, /* R148 - Haptics phase 2 intensity */
+ { 0x00000095, 0x0000 }, /* R149 - Haptics phase 2 duration */
+ { 0x00000096, 0x0000 }, /* R150 - Haptics phase 3 intensity */
+ { 0x00000097, 0x0000 }, /* R151 - Haptics phase 3 duration */
{ 0x00000100, 0x0002 }, /* R256 - Clock 32k 1 */
- { 0x00000101, 0x0304 }, /* R257 - System Clock 1 */
- { 0x00000102, 0x0011 }, /* R258 - Sample rate 1 */
- { 0x00000103, 0x0011 }, /* R259 - Sample rate 2 */
- { 0x00000104, 0x0011 }, /* R260 - Sample rate 3 */
- { 0x00000112, 0x0305 }, /* R274 - Async clock 1 */
- { 0x00000113, 0x0011 }, /* R275 - Async sample rate 1 */
+ { 0x00000101, 0x0304 }, /* R257 - System Clock 1 */
+ { 0x00000102, 0x0011 }, /* R258 - Sample rate 1 */
+ { 0x00000103, 0x0011 }, /* R259 - Sample rate 2 */
+ { 0x00000104, 0x0011 }, /* R260 - Sample rate 3 */
+ { 0x00000112, 0x0305 }, /* R274 - Async clock 1 */
+ { 0x00000113, 0x0011 }, /* R275 - Async sample rate 1 */
{ 0x00000114, 0x0011 }, /* R276 - Async sample rate 2 */
- { 0x00000149, 0x0000 }, /* R329 - Output system clock */
- { 0x0000014A, 0x0000 }, /* R330 - Output async clock */
- { 0x00000152, 0x0000 }, /* R338 - Rate Estimator 1 */
- { 0x00000153, 0x0000 }, /* R339 - Rate Estimator 2 */
- { 0x00000154, 0x0000 }, /* R340 - Rate Estimator 3 */
- { 0x00000155, 0x0000 }, /* R341 - Rate Estimator 4 */
- { 0x00000156, 0x0000 }, /* R342 - Rate Estimator 5 */
- { 0x00000161, 0x0000 }, /* R353 - Dynamic Frequency Scaling 1 */
+ { 0x00000149, 0x0000 }, /* R329 - Output system clock */
+ { 0x0000014A, 0x0000 }, /* R330 - Output async clock */
+ { 0x00000152, 0x0000 }, /* R338 - Rate Estimator 1 */
+ { 0x00000153, 0x0000 }, /* R339 - Rate Estimator 2 */
+ { 0x00000154, 0x0000 }, /* R340 - Rate Estimator 3 */
+ { 0x00000155, 0x0000 }, /* R341 - Rate Estimator 4 */
+ { 0x00000156, 0x0000 }, /* R342 - Rate Estimator 5 */
+ { 0x00000161, 0x0000 }, /* R353 - Dynamic Frequency Scaling 1 */
{ 0x00000171, 0x0000 }, /* R369 - FLL1 Control 1 */
- { 0x00000172, 0x0008 }, /* R370 - FLL1 Control 2 */
- { 0x00000173, 0x0018 }, /* R371 - FLL1 Control 3 */
- { 0x00000174, 0x007D }, /* R372 - FLL1 Control 4 */
- { 0x00000175, 0x0004 }, /* R373 - FLL1 Control 5 */
- { 0x00000176, 0x0000 }, /* R374 - FLL1 Control 6 */
+ { 0x00000172, 0x0008 }, /* R370 - FLL1 Control 2 */
+ { 0x00000173, 0x0018 }, /* R371 - FLL1 Control 3 */
+ { 0x00000174, 0x007D }, /* R372 - FLL1 Control 4 */
+ { 0x00000175, 0x0004 }, /* R373 - FLL1 Control 5 */
+ { 0x00000176, 0x0000 }, /* R374 - FLL1 Control 6 */
{ 0x00000179, 0x0000 }, /* R377 - FLL1 Control 7 */
- { 0x00000181, 0x0000 }, /* R385 - FLL1 Synchroniser 1 */
- { 0x00000182, 0x0000 }, /* R386 - FLL1 Synchroniser 2 */
- { 0x00000183, 0x0000 }, /* R387 - FLL1 Synchroniser 3 */
- { 0x00000184, 0x0000 }, /* R388 - FLL1 Synchroniser 4 */
- { 0x00000185, 0x0000 }, /* R389 - FLL1 Synchroniser 5 */
- { 0x00000186, 0x0000 }, /* R390 - FLL1 Synchroniser 6 */
+ { 0x00000181, 0x0000 }, /* R385 - FLL1 Synchroniser 1 */
+ { 0x00000182, 0x0000 }, /* R386 - FLL1 Synchroniser 2 */
+ { 0x00000183, 0x0000 }, /* R387 - FLL1 Synchroniser 3 */
+ { 0x00000184, 0x0000 }, /* R388 - FLL1 Synchroniser 4 */
+ { 0x00000185, 0x0000 }, /* R389 - FLL1 Synchroniser 5 */
+ { 0x00000186, 0x0000 }, /* R390 - FLL1 Synchroniser 6 */
{ 0x00000187, 0x0001 }, /* R391 - FLL1 Synchroniser 7 */
- { 0x00000189, 0x0000 }, /* R393 - FLL1 Spread Spectrum */
- { 0x0000018A, 0x0004 }, /* R394 - FLL1 GPIO Clock */
- { 0x00000191, 0x0000 }, /* R401 - FLL2 Control 1 */
- { 0x00000192, 0x0008 }, /* R402 - FLL2 Control 2 */
- { 0x00000193, 0x0018 }, /* R403 - FLL2 Control 3 */
- { 0x00000194, 0x007D }, /* R404 - FLL2 Control 4 */
- { 0x00000195, 0x0004 }, /* R405 - FLL2 Control 5 */
- { 0x00000196, 0x0000 }, /* R406 - FLL2 Control 6 */
+ { 0x00000189, 0x0000 }, /* R393 - FLL1 Spread Spectrum */
+ { 0x0000018A, 0x0004 }, /* R394 - FLL1 GPIO Clock */
+ { 0x00000191, 0x0000 }, /* R401 - FLL2 Control 1 */
+ { 0x00000192, 0x0008 }, /* R402 - FLL2 Control 2 */
+ { 0x00000193, 0x0018 }, /* R403 - FLL2 Control 3 */
+ { 0x00000194, 0x007D }, /* R404 - FLL2 Control 4 */
+ { 0x00000195, 0x0004 }, /* R405 - FLL2 Control 5 */
+ { 0x00000196, 0x0000 }, /* R406 - FLL2 Control 6 */
{ 0x00000199, 0x0000 }, /* R409 - FLL2 Control 7 */
- { 0x000001A1, 0x0000 }, /* R417 - FLL2 Synchroniser 1 */
- { 0x000001A2, 0x0000 }, /* R418 - FLL2 Synchroniser 2 */
- { 0x000001A3, 0x0000 }, /* R419 - FLL2 Synchroniser 3 */
- { 0x000001A4, 0x0000 }, /* R420 - FLL2 Synchroniser 4 */
- { 0x000001A5, 0x0000 }, /* R421 - FLL2 Synchroniser 5 */
- { 0x000001A6, 0x0000 }, /* R422 - FLL2 Synchroniser 6 */
+ { 0x000001A1, 0x0000 }, /* R417 - FLL2 Synchroniser 1 */
+ { 0x000001A2, 0x0000 }, /* R418 - FLL2 Synchroniser 2 */
+ { 0x000001A3, 0x0000 }, /* R419 - FLL2 Synchroniser 3 */
+ { 0x000001A4, 0x0000 }, /* R420 - FLL2 Synchroniser 4 */
+ { 0x000001A5, 0x0000 }, /* R421 - FLL2 Synchroniser 5 */
+ { 0x000001A6, 0x0000 }, /* R422 - FLL2 Synchroniser 6 */
{ 0x000001A7, 0x0001 }, /* R423 - FLL2 Synchroniser 7 */
- { 0x000001A9, 0x0000 }, /* R425 - FLL2 Spread Spectrum */
- { 0x000001AA, 0x0004 }, /* R426 - FLL2 GPIO Clock */
- { 0x00000200, 0x0006 }, /* R512 - Mic Charge Pump 1 */
- { 0x00000210, 0x00D4 }, /* R528 - LDO1 Control 1 */
+ { 0x000001A9, 0x0000 }, /* R425 - FLL2 Spread Spectrum */
+ { 0x000001AA, 0x0004 }, /* R426 - FLL2 GPIO Clock */
+ { 0x00000200, 0x0006 }, /* R512 - Mic Charge Pump 1 */
+ { 0x00000210, 0x00D4 }, /* R528 - LDO1 Control 1 */
{ 0x00000212, 0x0000 }, /* R530 - LDO1 Control 2 */
- { 0x00000213, 0x0344 }, /* R531 - LDO2 Control 1 */
- { 0x00000218, 0x01A6 }, /* R536 - Mic Bias Ctrl 1 */
- { 0x00000219, 0x01A6 }, /* R537 - Mic Bias Ctrl 2 */
- { 0x0000021A, 0x01A6 }, /* R538 - Mic Bias Ctrl 3 */
- { 0x00000293, 0x0000 }, /* R659 - Accessory Detect Mode 1 */
- { 0x0000029B, 0x0020 }, /* R667 - Headphone Detect 1 */
+ { 0x00000213, 0x0344 }, /* R531 - LDO2 Control 1 */
+ { 0x00000218, 0x01A6 }, /* R536 - Mic Bias Ctrl 1 */
+ { 0x00000219, 0x01A6 }, /* R537 - Mic Bias Ctrl 2 */
+ { 0x0000021A, 0x01A6 }, /* R538 - Mic Bias Ctrl 3 */
+ { 0x00000293, 0x0000 }, /* R659 - Accessory Detect Mode 1 */
+ { 0x0000029B, 0x0020 }, /* R667 - Headphone Detect 1 */
{ 0x000002A2, 0x0000 }, /* R674 - Micd clamp control */
- { 0x000002A3, 0x1102 }, /* R675 - Mic Detect 1 */
- { 0x000002A4, 0x009F }, /* R676 - Mic Detect 2 */
+ { 0x000002A3, 0x1102 }, /* R675 - Mic Detect 1 */
+ { 0x000002A4, 0x009F }, /* R676 - Mic Detect 2 */
{ 0x000002A6, 0x3737 }, /* R678 - Mic Detect Level 1 */
{ 0x000002A7, 0x2C37 }, /* R679 - Mic Detect Level 2 */
{ 0x000002A8, 0x1422 }, /* R680 - Mic Detect Level 3 */
{ 0x000002A9, 0x030A }, /* R681 - Mic Detect Level 4 */
- { 0x000002C3, 0x0000 }, /* R707 - Mic noise mix control 1 */
- { 0x000002CB, 0x0000 }, /* R715 - Isolation control */
- { 0x000002D3, 0x0000 }, /* R723 - Jack detect analogue */
- { 0x00000300, 0x0000 }, /* R768 - Input Enables */
- { 0x00000308, 0x0000 }, /* R776 - Input Rate */
- { 0x00000309, 0x0022 }, /* R777 - Input Volume Ramp */
- { 0x00000310, 0x2080 }, /* R784 - IN1L Control */
- { 0x00000311, 0x0180 }, /* R785 - ADC Digital Volume 1L */
- { 0x00000312, 0x0000 }, /* R786 - DMIC1L Control */
- { 0x00000314, 0x0080 }, /* R788 - IN1R Control */
- { 0x00000315, 0x0180 }, /* R789 - ADC Digital Volume 1R */
- { 0x00000316, 0x0000 }, /* R790 - DMIC1R Control */
- { 0x00000318, 0x2080 }, /* R792 - IN2L Control */
- { 0x00000319, 0x0180 }, /* R793 - ADC Digital Volume 2L */
- { 0x0000031A, 0x0000 }, /* R794 - DMIC2L Control */
- { 0x0000031C, 0x0080 }, /* R796 - IN2R Control */
- { 0x0000031D, 0x0180 }, /* R797 - ADC Digital Volume 2R */
- { 0x0000031E, 0x0000 }, /* R798 - DMIC2R Control */
- { 0x00000320, 0x2080 }, /* R800 - IN3L Control */
- { 0x00000321, 0x0180 }, /* R801 - ADC Digital Volume 3L */
- { 0x00000322, 0x0000 }, /* R802 - DMIC3L Control */
- { 0x00000324, 0x0080 }, /* R804 - IN3R Control */
- { 0x00000325, 0x0180 }, /* R805 - ADC Digital Volume 3R */
- { 0x00000326, 0x0000 }, /* R806 - DMIC3R Control */
- { 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */
- { 0x00000408, 0x0000 }, /* R1032 - Output Rate 1 */
- { 0x00000409, 0x0022 }, /* R1033 - Output Volume Ramp */
+ { 0x000002C3, 0x0000 }, /* R707 - Mic noise mix control 1 */
+ { 0x000002CB, 0x0000 }, /* R715 - Isolation control */
+ { 0x000002D3, 0x0000 }, /* R723 - Jack detect analogue */
+ { 0x00000300, 0x0000 }, /* R768 - Input Enables */
+ { 0x00000308, 0x0000 }, /* R776 - Input Rate */
+ { 0x00000309, 0x0022 }, /* R777 - Input Volume Ramp */
+ { 0x00000310, 0x2080 }, /* R784 - IN1L Control */
+ { 0x00000311, 0x0180 }, /* R785 - ADC Digital Volume 1L */
+ { 0x00000312, 0x0000 }, /* R786 - DMIC1L Control */
+ { 0x00000314, 0x0080 }, /* R788 - IN1R Control */
+ { 0x00000315, 0x0180 }, /* R789 - ADC Digital Volume 1R */
+ { 0x00000316, 0x0000 }, /* R790 - DMIC1R Control */
+ { 0x00000318, 0x2080 }, /* R792 - IN2L Control */
+ { 0x00000319, 0x0180 }, /* R793 - ADC Digital Volume 2L */
+ { 0x0000031A, 0x0000 }, /* R794 - DMIC2L Control */
+ { 0x0000031C, 0x0080 }, /* R796 - IN2R Control */
+ { 0x0000031D, 0x0180 }, /* R797 - ADC Digital Volume 2R */
+ { 0x0000031E, 0x0000 }, /* R798 - DMIC2R Control */
+ { 0x00000320, 0x2080 }, /* R800 - IN3L Control */
+ { 0x00000321, 0x0180 }, /* R801 - ADC Digital Volume 3L */
+ { 0x00000322, 0x0000 }, /* R802 - DMIC3L Control */
+ { 0x00000324, 0x0080 }, /* R804 - IN3R Control */
+ { 0x00000325, 0x0180 }, /* R805 - ADC Digital Volume 3R */
+ { 0x00000326, 0x0000 }, /* R806 - DMIC3R Control */
+ { 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */
+ { 0x00000408, 0x0000 }, /* R1032 - Output Rate 1 */
+ { 0x00000409, 0x0022 }, /* R1033 - Output Volume Ramp */
{ 0x00000410, 0x6080 }, /* R1040 - Output Path Config 1L */
- { 0x00000411, 0x0180 }, /* R1041 - DAC Digital Volume 1L */
+ { 0x00000411, 0x0180 }, /* R1041 - DAC Digital Volume 1L */
{ 0x00000412, 0x0081 }, /* R1042 - DAC Volume Limit 1L */
- { 0x00000413, 0x0001 }, /* R1043 - Noise Gate Select 1L */
- { 0x00000414, 0x0080 }, /* R1044 - Output Path Config 1R */
- { 0x00000415, 0x0180 }, /* R1045 - DAC Digital Volume 1R */
+ { 0x00000413, 0x0001 }, /* R1043 - Noise Gate Select 1L */
+ { 0x00000414, 0x0080 }, /* R1044 - Output Path Config 1R */
+ { 0x00000415, 0x0180 }, /* R1045 - DAC Digital Volume 1R */
{ 0x00000416, 0x0081 }, /* R1046 - DAC Volume Limit 1R */
- { 0x00000417, 0x0002 }, /* R1047 - Noise Gate Select 1R */
+ { 0x00000417, 0x0002 }, /* R1047 - Noise Gate Select 1R */
{ 0x00000418, 0xA080 }, /* R1048 - Output Path Config 2L */
- { 0x00000419, 0x0180 }, /* R1049 - DAC Digital Volume 2L */
+ { 0x00000419, 0x0180 }, /* R1049 - DAC Digital Volume 2L */
{ 0x0000041A, 0x0081 }, /* R1050 - DAC Volume Limit 2L */
- { 0x0000041B, 0x0004 }, /* R1051 - Noise Gate Select 2L */
- { 0x0000041C, 0x0080 }, /* R1052 - Output Path Config 2R */
- { 0x0000041D, 0x0180 }, /* R1053 - DAC Digital Volume 2R */
+ { 0x0000041B, 0x0004 }, /* R1051 - Noise Gate Select 2L */
+ { 0x0000041C, 0x0080 }, /* R1052 - Output Path Config 2R */
+ { 0x0000041D, 0x0180 }, /* R1053 - DAC Digital Volume 2R */
{ 0x0000041E, 0x0081 }, /* R1054 - DAC Volume Limit 2R */
- { 0x0000041F, 0x0008 }, /* R1055 - Noise Gate Select 2R */
+ { 0x0000041F, 0x0008 }, /* R1055 - Noise Gate Select 2R */
{ 0x00000420, 0xA080 }, /* R1056 - Output Path Config 3L */
- { 0x00000421, 0x0180 }, /* R1057 - DAC Digital Volume 3L */
+ { 0x00000421, 0x0180 }, /* R1057 - DAC Digital Volume 3L */
{ 0x00000422, 0x0081 }, /* R1058 - DAC Volume Limit 3L */
- { 0x00000423, 0x0010 }, /* R1059 - Noise Gate Select 3L */
+ { 0x00000423, 0x0010 }, /* R1059 - Noise Gate Select 3L */
{ 0x00000428, 0xE000 }, /* R1064 - Output Path Config 4L */
- { 0x00000429, 0x0180 }, /* R1065 - DAC Digital Volume 4L */
+ { 0x00000429, 0x0180 }, /* R1065 - DAC Digital Volume 4L */
{ 0x0000042A, 0x0081 }, /* R1066 - Out Volume 4L */
- { 0x0000042B, 0x0040 }, /* R1067 - Noise Gate Select 4L */
- { 0x0000042D, 0x0180 }, /* R1069 - DAC Digital Volume 4R */
+ { 0x0000042B, 0x0040 }, /* R1067 - Noise Gate Select 4L */
+ { 0x0000042D, 0x0180 }, /* R1069 - DAC Digital Volume 4R */
{ 0x0000042E, 0x0081 }, /* R1070 - Out Volume 4R */
- { 0x0000042F, 0x0080 }, /* R1071 - Noise Gate Select 4R */
- { 0x00000430, 0x0000 }, /* R1072 - Output Path Config 5L */
- { 0x00000431, 0x0180 }, /* R1073 - DAC Digital Volume 5L */
+ { 0x0000042F, 0x0080 }, /* R1071 - Noise Gate Select 4R */
+ { 0x00000430, 0x0000 }, /* R1072 - Output Path Config 5L */
+ { 0x00000431, 0x0180 }, /* R1073 - DAC Digital Volume 5L */
{ 0x00000432, 0x0081 }, /* R1074 - DAC Volume Limit 5L */
- { 0x00000433, 0x0100 }, /* R1075 - Noise Gate Select 5L */
- { 0x00000435, 0x0180 }, /* R1077 - DAC Digital Volume 5R */
+ { 0x00000433, 0x0100 }, /* R1075 - Noise Gate Select 5L */
+ { 0x00000435, 0x0180 }, /* R1077 - DAC Digital Volume 5R */
{ 0x00000436, 0x0081 }, /* R1078 - DAC Volume Limit 5R */
{ 0x00000437, 0x0200 }, /* R1079 - Noise Gate Select 5R */
{ 0x00000440, 0x0FFF }, /* R1088 - DRE Enable */
{ 0x00000442, 0x3F0A }, /* R1090 - DRE Control 2 */
{ 0x00000443, 0xDC1F }, /* R1090 - DRE Control 3 */
- { 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */
+ { 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */
{ 0x00000458, 0x000B }, /* R1112 - Noise Gate Control */
- { 0x00000490, 0x0069 }, /* R1168 - PDM SPK1 CTRL 1 */
- { 0x00000491, 0x0000 }, /* R1169 - PDM SPK1 CTRL 2 */
- { 0x00000500, 0x000C }, /* R1280 - AIF1 BCLK Ctrl */
- { 0x00000501, 0x0008 }, /* R1281 - AIF1 Tx Pin Ctrl */
- { 0x00000502, 0x0000 }, /* R1282 - AIF1 Rx Pin Ctrl */
- { 0x00000503, 0x0000 }, /* R1283 - AIF1 Rate Ctrl */
- { 0x00000504, 0x0000 }, /* R1284 - AIF1 Format */
- { 0x00000505, 0x0040 }, /* R1285 - AIF1 Tx BCLK Rate */
- { 0x00000506, 0x0040 }, /* R1286 - AIF1 Rx BCLK Rate */
- { 0x00000507, 0x1818 }, /* R1287 - AIF1 Frame Ctrl 1 */
- { 0x00000508, 0x1818 }, /* R1288 - AIF1 Frame Ctrl 2 */
- { 0x00000509, 0x0000 }, /* R1289 - AIF1 Frame Ctrl 3 */
- { 0x0000050A, 0x0001 }, /* R1290 - AIF1 Frame Ctrl 4 */
- { 0x0000050B, 0x0002 }, /* R1291 - AIF1 Frame Ctrl 5 */
- { 0x0000050C, 0x0003 }, /* R1292 - AIF1 Frame Ctrl 6 */
- { 0x0000050D, 0x0004 }, /* R1293 - AIF1 Frame Ctrl 7 */
- { 0x0000050E, 0x0005 }, /* R1294 - AIF1 Frame Ctrl 8 */
- { 0x0000050F, 0x0006 }, /* R1295 - AIF1 Frame Ctrl 9 */
- { 0x00000510, 0x0007 }, /* R1296 - AIF1 Frame Ctrl 10 */
- { 0x00000511, 0x0000 }, /* R1297 - AIF1 Frame Ctrl 11 */
- { 0x00000512, 0x0001 }, /* R1298 - AIF1 Frame Ctrl 12 */
- { 0x00000513, 0x0002 }, /* R1299 - AIF1 Frame Ctrl 13 */
- { 0x00000514, 0x0003 }, /* R1300 - AIF1 Frame Ctrl 14 */
- { 0x00000515, 0x0004 }, /* R1301 - AIF1 Frame Ctrl 15 */
- { 0x00000516, 0x0005 }, /* R1302 - AIF1 Frame Ctrl 16 */
- { 0x00000517, 0x0006 }, /* R1303 - AIF1 Frame Ctrl 17 */
- { 0x00000518, 0x0007 }, /* R1304 - AIF1 Frame Ctrl 18 */
- { 0x00000519, 0x0000 }, /* R1305 - AIF1 Tx Enables */
- { 0x0000051A, 0x0000 }, /* R1306 - AIF1 Rx Enables */
- { 0x00000540, 0x000C }, /* R1344 - AIF2 BCLK Ctrl */
- { 0x00000541, 0x0008 }, /* R1345 - AIF2 Tx Pin Ctrl */
- { 0x00000542, 0x0000 }, /* R1346 - AIF2 Rx Pin Ctrl */
- { 0x00000543, 0x0000 }, /* R1347 - AIF2 Rate Ctrl */
- { 0x00000544, 0x0000 }, /* R1348 - AIF2 Format */
- { 0x00000545, 0x0040 }, /* R1349 - AIF2 Tx BCLK Rate */
- { 0x00000546, 0x0040 }, /* R1350 - AIF2 Rx BCLK Rate */
- { 0x00000547, 0x1818 }, /* R1351 - AIF2 Frame Ctrl 1 */
- { 0x00000548, 0x1818 }, /* R1352 - AIF2 Frame Ctrl 2 */
- { 0x00000549, 0x0000 }, /* R1353 - AIF2 Frame Ctrl 3 */
- { 0x0000054A, 0x0001 }, /* R1354 - AIF2 Frame Ctrl 4 */
- { 0x00000551, 0x0000 }, /* R1361 - AIF2 Frame Ctrl 11 */
- { 0x00000552, 0x0001 }, /* R1362 - AIF2 Frame Ctrl 12 */
- { 0x00000559, 0x0000 }, /* R1369 - AIF2 Tx Enables */
- { 0x0000055A, 0x0000 }, /* R1370 - AIF2 Rx Enables */
- { 0x00000580, 0x000C }, /* R1408 - AIF3 BCLK Ctrl */
- { 0x00000581, 0x0008 }, /* R1409 - AIF3 Tx Pin Ctrl */
- { 0x00000582, 0x0000 }, /* R1410 - AIF3 Rx Pin Ctrl */
- { 0x00000583, 0x0000 }, /* R1411 - AIF3 Rate Ctrl */
- { 0x00000584, 0x0000 }, /* R1412 - AIF3 Format */
- { 0x00000585, 0x0040 }, /* R1413 - AIF3 Tx BCLK Rate */
- { 0x00000586, 0x0040 }, /* R1414 - AIF3 Rx BCLK Rate */
- { 0x00000587, 0x1818 }, /* R1415 - AIF3 Frame Ctrl 1 */
- { 0x00000588, 0x1818 }, /* R1416 - AIF3 Frame Ctrl 2 */
- { 0x00000589, 0x0000 }, /* R1417 - AIF3 Frame Ctrl 3 */
- { 0x0000058A, 0x0001 }, /* R1418 - AIF3 Frame Ctrl 4 */
- { 0x00000591, 0x0000 }, /* R1425 - AIF3 Frame Ctrl 11 */
- { 0x00000592, 0x0001 }, /* R1426 - AIF3 Frame Ctrl 12 */
- { 0x00000599, 0x0000 }, /* R1433 - AIF3 Tx Enables */
- { 0x0000059A, 0x0000 }, /* R1434 - AIF3 Rx Enables */
- { 0x000005E3, 0x0004 }, /* R1507 - SLIMbus Framer Ref Gear */
- { 0x000005E5, 0x0000 }, /* R1509 - SLIMbus Rates 1 */
- { 0x000005E6, 0x0000 }, /* R1510 - SLIMbus Rates 2 */
- { 0x000005E7, 0x0000 }, /* R1511 - SLIMbus Rates 3 */
- { 0x000005E8, 0x0000 }, /* R1512 - SLIMbus Rates 4 */
- { 0x000005E9, 0x0000 }, /* R1513 - SLIMbus Rates 5 */
- { 0x000005EA, 0x0000 }, /* R1514 - SLIMbus Rates 6 */
- { 0x000005EB, 0x0000 }, /* R1515 - SLIMbus Rates 7 */
- { 0x000005EC, 0x0000 }, /* R1516 - SLIMbus Rates 8 */
- { 0x000005F5, 0x0000 }, /* R1525 - SLIMbus RX Channel Enable */
- { 0x000005F6, 0x0000 }, /* R1526 - SLIMbus TX Channel Enable */
- { 0x00000640, 0x0000 }, /* R1600 - PWM1MIX Input 1 Source */
- { 0x00000641, 0x0080 }, /* R1601 - PWM1MIX Input 1 Volume */
- { 0x00000642, 0x0000 }, /* R1602 - PWM1MIX Input 2 Source */
- { 0x00000643, 0x0080 }, /* R1603 - PWM1MIX Input 2 Volume */
- { 0x00000644, 0x0000 }, /* R1604 - PWM1MIX Input 3 Source */
- { 0x00000645, 0x0080 }, /* R1605 - PWM1MIX Input 3 Volume */
- { 0x00000646, 0x0000 }, /* R1606 - PWM1MIX Input 4 Source */
- { 0x00000647, 0x0080 }, /* R1607 - PWM1MIX Input 4 Volume */
- { 0x00000648, 0x0000 }, /* R1608 - PWM2MIX Input 1 Source */
- { 0x00000649, 0x0080 }, /* R1609 - PWM2MIX Input 1 Volume */
- { 0x0000064A, 0x0000 }, /* R1610 - PWM2MIX Input 2 Source */
- { 0x0000064B, 0x0080 }, /* R1611 - PWM2MIX Input 2 Volume */
- { 0x0000064C, 0x0000 }, /* R1612 - PWM2MIX Input 3 Source */
- { 0x0000064D, 0x0080 }, /* R1613 - PWM2MIX Input 3 Volume */
- { 0x0000064E, 0x0000 }, /* R1614 - PWM2MIX Input 4 Source */
- { 0x0000064F, 0x0080 }, /* R1615 - PWM2MIX Input 4 Volume */
- { 0x00000660, 0x0000 }, /* R1632 - MICMIX Input 1 Source */
- { 0x00000661, 0x0080 }, /* R1633 - MICMIX Input 1 Volume */
- { 0x00000662, 0x0000 }, /* R1634 - MICMIX Input 2 Source */
- { 0x00000663, 0x0080 }, /* R1635 - MICMIX Input 2 Volume */
- { 0x00000664, 0x0000 }, /* R1636 - MICMIX Input 3 Source */
- { 0x00000665, 0x0080 }, /* R1637 - MICMIX Input 3 Volume */
- { 0x00000666, 0x0000 }, /* R1638 - MICMIX Input 4 Source */
- { 0x00000667, 0x0080 }, /* R1639 - MICMIX Input 4 Volume */
- { 0x00000668, 0x0000 }, /* R1640 - NOISEMIX Input 1 Source */
- { 0x00000669, 0x0080 }, /* R1641 - NOISEMIX Input 1 Volume */
- { 0x0000066A, 0x0000 }, /* R1642 - NOISEMIX Input 2 Source */
- { 0x0000066B, 0x0080 }, /* R1643 - NOISEMIX Input 2 Volume */
- { 0x0000066C, 0x0000 }, /* R1644 - NOISEMIX Input 3 Source */
- { 0x0000066D, 0x0080 }, /* R1645 - NOISEMIX Input 3 Volume */
- { 0x0000066E, 0x0000 }, /* R1646 - NOISEMIX Input 4 Source */
- { 0x0000066F, 0x0080 }, /* R1647 - NOISEMIX Input 4 Volume */
- { 0x00000680, 0x0000 }, /* R1664 - OUT1LMIX Input 1 Source */
- { 0x00000681, 0x0080 }, /* R1665 - OUT1LMIX Input 1 Volume */
- { 0x00000682, 0x0000 }, /* R1666 - OUT1LMIX Input 2 Source */
- { 0x00000683, 0x0080 }, /* R1667 - OUT1LMIX Input 2 Volume */
- { 0x00000684, 0x0000 }, /* R1668 - OUT1LMIX Input 3 Source */
- { 0x00000685, 0x0080 }, /* R1669 - OUT1LMIX Input 3 Volume */
- { 0x00000686, 0x0000 }, /* R1670 - OUT1LMIX Input 4 Source */
- { 0x00000687, 0x0080 }, /* R1671 - OUT1LMIX Input 4 Volume */
- { 0x00000688, 0x0000 }, /* R1672 - OUT1RMIX Input 1 Source */
- { 0x00000689, 0x0080 }, /* R1673 - OUT1RMIX Input 1 Volume */
- { 0x0000068A, 0x0000 }, /* R1674 - OUT1RMIX Input 2 Source */
- { 0x0000068B, 0x0080 }, /* R1675 - OUT1RMIX Input 2 Volume */
- { 0x0000068C, 0x0000 }, /* R1676 - OUT1RMIX Input 3 Source */
- { 0x0000068D, 0x0080 }, /* R1677 - OUT1RMIX Input 3 Volume */
- { 0x0000068E, 0x0000 }, /* R1678 - OUT1RMIX Input 4 Source */
- { 0x0000068F, 0x0080 }, /* R1679 - OUT1RMIX Input 4 Volume */
- { 0x00000690, 0x0000 }, /* R1680 - OUT2LMIX Input 1 Source */
- { 0x00000691, 0x0080 }, /* R1681 - OUT2LMIX Input 1 Volume */
- { 0x00000692, 0x0000 }, /* R1682 - OUT2LMIX Input 2 Source */
- { 0x00000693, 0x0080 }, /* R1683 - OUT2LMIX Input 2 Volume */
- { 0x00000694, 0x0000 }, /* R1684 - OUT2LMIX Input 3 Source */
- { 0x00000695, 0x0080 }, /* R1685 - OUT2LMIX Input 3 Volume */
- { 0x00000696, 0x0000 }, /* R1686 - OUT2LMIX Input 4 Source */
- { 0x00000697, 0x0080 }, /* R1687 - OUT2LMIX Input 4 Volume */
- { 0x00000698, 0x0000 }, /* R1688 - OUT2RMIX Input 1 Source */
- { 0x00000699, 0x0080 }, /* R1689 - OUT2RMIX Input 1 Volume */
- { 0x0000069A, 0x0000 }, /* R1690 - OUT2RMIX Input 2 Source */
- { 0x0000069B, 0x0080 }, /* R1691 - OUT2RMIX Input 2 Volume */
- { 0x0000069C, 0x0000 }, /* R1692 - OUT2RMIX Input 3 Source */
- { 0x0000069D, 0x0080 }, /* R1693 - OUT2RMIX Input 3 Volume */
- { 0x0000069E, 0x0000 }, /* R1694 - OUT2RMIX Input 4 Source */
- { 0x0000069F, 0x0080 }, /* R1695 - OUT2RMIX Input 4 Volume */
- { 0x000006A0, 0x0000 }, /* R1696 - OUT3LMIX Input 1 Source */
- { 0x000006A1, 0x0080 }, /* R1697 - OUT3LMIX Input 1 Volume */
- { 0x000006A2, 0x0000 }, /* R1698 - OUT3LMIX Input 2 Source */
- { 0x000006A3, 0x0080 }, /* R1699 - OUT3LMIX Input 2 Volume */
- { 0x000006A4, 0x0000 }, /* R1700 - OUT3LMIX Input 3 Source */
- { 0x000006A5, 0x0080 }, /* R1701 - OUT3LMIX Input 3 Volume */
- { 0x000006A6, 0x0000 }, /* R1702 - OUT3LMIX Input 4 Source */
- { 0x000006A7, 0x0080 }, /* R1703 - OUT3LMIX Input 4 Volume */
- { 0x000006B0, 0x0000 }, /* R1712 - OUT4LMIX Input 1 Source */
- { 0x000006B1, 0x0080 }, /* R1713 - OUT4LMIX Input 1 Volume */
- { 0x000006B2, 0x0000 }, /* R1714 - OUT4LMIX Input 2 Source */
- { 0x000006B3, 0x0080 }, /* R1715 - OUT4LMIX Input 2 Volume */
- { 0x000006B4, 0x0000 }, /* R1716 - OUT4LMIX Input 3 Source */
- { 0x000006B5, 0x0080 }, /* R1717 - OUT4LMIX Input 3 Volume */
- { 0x000006B6, 0x0000 }, /* R1718 - OUT4LMIX Input 4 Source */
- { 0x000006B7, 0x0080 }, /* R1719 - OUT4LMIX Input 4 Volume */
- { 0x000006B8, 0x0000 }, /* R1720 - OUT4RMIX Input 1 Source */
- { 0x000006B9, 0x0080 }, /* R1721 - OUT4RMIX Input 1 Volume */
- { 0x000006BA, 0x0000 }, /* R1722 - OUT4RMIX Input 2 Source */
- { 0x000006BB, 0x0080 }, /* R1723 - OUT4RMIX Input 2 Volume */
- { 0x000006BC, 0x0000 }, /* R1724 - OUT4RMIX Input 3 Source */
- { 0x000006BD, 0x0080 }, /* R1725 - OUT4RMIX Input 3 Volume */
- { 0x000006BE, 0x0000 }, /* R1726 - OUT4RMIX Input 4 Source */
- { 0x000006BF, 0x0080 }, /* R1727 - OUT4RMIX Input 4 Volume */
- { 0x000006C0, 0x0000 }, /* R1728 - OUT5LMIX Input 1 Source */
- { 0x000006C1, 0x0080 }, /* R1729 - OUT5LMIX Input 1 Volume */
- { 0x000006C2, 0x0000 }, /* R1730 - OUT5LMIX Input 2 Source */
- { 0x000006C3, 0x0080 }, /* R1731 - OUT5LMIX Input 2 Volume */
- { 0x000006C4, 0x0000 }, /* R1732 - OUT5LMIX Input 3 Source */
- { 0x000006C5, 0x0080 }, /* R1733 - OUT5LMIX Input 3 Volume */
- { 0x000006C6, 0x0000 }, /* R1734 - OUT5LMIX Input 4 Source */
- { 0x000006C7, 0x0080 }, /* R1735 - OUT5LMIX Input 4 Volume */
- { 0x000006C8, 0x0000 }, /* R1736 - OUT5RMIX Input 1 Source */
- { 0x000006C9, 0x0080 }, /* R1737 - OUT5RMIX Input 1 Volume */
- { 0x000006CA, 0x0000 }, /* R1738 - OUT5RMIX Input 2 Source */
- { 0x000006CB, 0x0080 }, /* R1739 - OUT5RMIX Input 2 Volume */
- { 0x000006CC, 0x0000 }, /* R1740 - OUT5RMIX Input 3 Source */
- { 0x000006CD, 0x0080 }, /* R1741 - OUT5RMIX Input 3 Volume */
- { 0x000006CE, 0x0000 }, /* R1742 - OUT5RMIX Input 4 Source */
- { 0x000006CF, 0x0080 }, /* R1743 - OUT5RMIX Input 4 Volume */
- { 0x00000700, 0x0000 }, /* R1792 - AIF1TX1MIX Input 1 Source */
- { 0x00000701, 0x0080 }, /* R1793 - AIF1TX1MIX Input 1 Volume */
- { 0x00000702, 0x0000 }, /* R1794 - AIF1TX1MIX Input 2 Source */
- { 0x00000703, 0x0080 }, /* R1795 - AIF1TX1MIX Input 2 Volume */
- { 0x00000704, 0x0000 }, /* R1796 - AIF1TX1MIX Input 3 Source */
- { 0x00000705, 0x0080 }, /* R1797 - AIF1TX1MIX Input 3 Volume */
- { 0x00000706, 0x0000 }, /* R1798 - AIF1TX1MIX Input 4 Source */
- { 0x00000707, 0x0080 }, /* R1799 - AIF1TX1MIX Input 4 Volume */
- { 0x00000708, 0x0000 }, /* R1800 - AIF1TX2MIX Input 1 Source */
- { 0x00000709, 0x0080 }, /* R1801 - AIF1TX2MIX Input 1 Volume */
- { 0x0000070A, 0x0000 }, /* R1802 - AIF1TX2MIX Input 2 Source */
- { 0x0000070B, 0x0080 }, /* R1803 - AIF1TX2MIX Input 2 Volume */
- { 0x0000070C, 0x0000 }, /* R1804 - AIF1TX2MIX Input 3 Source */
- { 0x0000070D, 0x0080 }, /* R1805 - AIF1TX2MIX Input 3 Volume */
- { 0x0000070E, 0x0000 }, /* R1806 - AIF1TX2MIX Input 4 Source */
- { 0x0000070F, 0x0080 }, /* R1807 - AIF1TX2MIX Input 4 Volume */
- { 0x00000710, 0x0000 }, /* R1808 - AIF1TX3MIX Input 1 Source */
- { 0x00000711, 0x0080 }, /* R1809 - AIF1TX3MIX Input 1 Volume */
- { 0x00000712, 0x0000 }, /* R1810 - AIF1TX3MIX Input 2 Source */
- { 0x00000713, 0x0080 }, /* R1811 - AIF1TX3MIX Input 2 Volume */
- { 0x00000714, 0x0000 }, /* R1812 - AIF1TX3MIX Input 3 Source */
- { 0x00000715, 0x0080 }, /* R1813 - AIF1TX3MIX Input 3 Volume */
- { 0x00000716, 0x0000 }, /* R1814 - AIF1TX3MIX Input 4 Source */
- { 0x00000717, 0x0080 }, /* R1815 - AIF1TX3MIX Input 4 Volume */
- { 0x00000718, 0x0000 }, /* R1816 - AIF1TX4MIX Input 1 Source */
- { 0x00000719, 0x0080 }, /* R1817 - AIF1TX4MIX Input 1 Volume */
- { 0x0000071A, 0x0000 }, /* R1818 - AIF1TX4MIX Input 2 Source */
- { 0x0000071B, 0x0080 }, /* R1819 - AIF1TX4MIX Input 2 Volume */
- { 0x0000071C, 0x0000 }, /* R1820 - AIF1TX4MIX Input 3 Source */
- { 0x0000071D, 0x0080 }, /* R1821 - AIF1TX4MIX Input 3 Volume */
- { 0x0000071E, 0x0000 }, /* R1822 - AIF1TX4MIX Input 4 Source */
- { 0x0000071F, 0x0080 }, /* R1823 - AIF1TX4MIX Input 4 Volume */
- { 0x00000720, 0x0000 }, /* R1824 - AIF1TX5MIX Input 1 Source */
- { 0x00000721, 0x0080 }, /* R1825 - AIF1TX5MIX Input 1 Volume */
- { 0x00000722, 0x0000 }, /* R1826 - AIF1TX5MIX Input 2 Source */
- { 0x00000723, 0x0080 }, /* R1827 - AIF1TX5MIX Input 2 Volume */
- { 0x00000724, 0x0000 }, /* R1828 - AIF1TX5MIX Input 3 Source */
- { 0x00000725, 0x0080 }, /* R1829 - AIF1TX5MIX Input 3 Volume */
- { 0x00000726, 0x0000 }, /* R1830 - AIF1TX5MIX Input 4 Source */
- { 0x00000727, 0x0080 }, /* R1831 - AIF1TX5MIX Input 4 Volume */
- { 0x00000728, 0x0000 }, /* R1832 - AIF1TX6MIX Input 1 Source */
- { 0x00000729, 0x0080 }, /* R1833 - AIF1TX6MIX Input 1 Volume */
- { 0x0000072A, 0x0000 }, /* R1834 - AIF1TX6MIX Input 2 Source */
- { 0x0000072B, 0x0080 }, /* R1835 - AIF1TX6MIX Input 2 Volume */
- { 0x0000072C, 0x0000 }, /* R1836 - AIF1TX6MIX Input 3 Source */
- { 0x0000072D, 0x0080 }, /* R1837 - AIF1TX6MIX Input 3 Volume */
- { 0x0000072E, 0x0000 }, /* R1838 - AIF1TX6MIX Input 4 Source */
- { 0x0000072F, 0x0080 }, /* R1839 - AIF1TX6MIX Input 4 Volume */
- { 0x00000730, 0x0000 }, /* R1840 - AIF1TX7MIX Input 1 Source */
- { 0x00000731, 0x0080 }, /* R1841 - AIF1TX7MIX Input 1 Volume */
- { 0x00000732, 0x0000 }, /* R1842 - AIF1TX7MIX Input 2 Source */
- { 0x00000733, 0x0080 }, /* R1843 - AIF1TX7MIX Input 2 Volume */
- { 0x00000734, 0x0000 }, /* R1844 - AIF1TX7MIX Input 3 Source */
- { 0x00000735, 0x0080 }, /* R1845 - AIF1TX7MIX Input 3 Volume */
- { 0x00000736, 0x0000 }, /* R1846 - AIF1TX7MIX Input 4 Source */
- { 0x00000737, 0x0080 }, /* R1847 - AIF1TX7MIX Input 4 Volume */
- { 0x00000738, 0x0000 }, /* R1848 - AIF1TX8MIX Input 1 Source */
- { 0x00000739, 0x0080 }, /* R1849 - AIF1TX8MIX Input 1 Volume */
- { 0x0000073A, 0x0000 }, /* R1850 - AIF1TX8MIX Input 2 Source */
- { 0x0000073B, 0x0080 }, /* R1851 - AIF1TX8MIX Input 2 Volume */
- { 0x0000073C, 0x0000 }, /* R1852 - AIF1TX8MIX Input 3 Source */
- { 0x0000073D, 0x0080 }, /* R1853 - AIF1TX8MIX Input 3 Volume */
- { 0x0000073E, 0x0000 }, /* R1854 - AIF1TX8MIX Input 4 Source */
- { 0x0000073F, 0x0080 }, /* R1855 - AIF1TX8MIX Input 4 Volume */
- { 0x00000740, 0x0000 }, /* R1856 - AIF2TX1MIX Input 1 Source */
- { 0x00000741, 0x0080 }, /* R1857 - AIF2TX1MIX Input 1 Volume */
- { 0x00000742, 0x0000 }, /* R1858 - AIF2TX1MIX Input 2 Source */
- { 0x00000743, 0x0080 }, /* R1859 - AIF2TX1MIX Input 2 Volume */
- { 0x00000744, 0x0000 }, /* R1860 - AIF2TX1MIX Input 3 Source */
- { 0x00000745, 0x0080 }, /* R1861 - AIF2TX1MIX Input 3 Volume */
- { 0x00000746, 0x0000 }, /* R1862 - AIF2TX1MIX Input 4 Source */
- { 0x00000747, 0x0080 }, /* R1863 - AIF2TX1MIX Input 4 Volume */
- { 0x00000748, 0x0000 }, /* R1864 - AIF2TX2MIX Input 1 Source */
- { 0x00000749, 0x0080 }, /* R1865 - AIF2TX2MIX Input 1 Volume */
- { 0x0000074A, 0x0000 }, /* R1866 - AIF2TX2MIX Input 2 Source */
- { 0x0000074B, 0x0080 }, /* R1867 - AIF2TX2MIX Input 2 Volume */
- { 0x0000074C, 0x0000 }, /* R1868 - AIF2TX2MIX Input 3 Source */
- { 0x0000074D, 0x0080 }, /* R1869 - AIF2TX2MIX Input 3 Volume */
- { 0x0000074E, 0x0000 }, /* R1870 - AIF2TX2MIX Input 4 Source */
- { 0x0000074F, 0x0080 }, /* R1871 - AIF2TX2MIX Input 4 Volume */
- { 0x00000780, 0x0000 }, /* R1920 - AIF3TX1MIX Input 1 Source */
- { 0x00000781, 0x0080 }, /* R1921 - AIF3TX1MIX Input 1 Volume */
- { 0x00000782, 0x0000 }, /* R1922 - AIF3TX1MIX Input 2 Source */
- { 0x00000783, 0x0080 }, /* R1923 - AIF3TX1MIX Input 2 Volume */
- { 0x00000784, 0x0000 }, /* R1924 - AIF3TX1MIX Input 3 Source */
- { 0x00000785, 0x0080 }, /* R1925 - AIF3TX1MIX Input 3 Volume */
- { 0x00000786, 0x0000 }, /* R1926 - AIF3TX1MIX Input 4 Source */
- { 0x00000787, 0x0080 }, /* R1927 - AIF3TX1MIX Input 4 Volume */
- { 0x00000788, 0x0000 }, /* R1928 - AIF3TX2MIX Input 1 Source */
- { 0x00000789, 0x0080 }, /* R1929 - AIF3TX2MIX Input 1 Volume */
- { 0x0000078A, 0x0000 }, /* R1930 - AIF3TX2MIX Input 2 Source */
- { 0x0000078B, 0x0080 }, /* R1931 - AIF3TX2MIX Input 2 Volume */
- { 0x0000078C, 0x0000 }, /* R1932 - AIF3TX2MIX Input 3 Source */
- { 0x0000078D, 0x0080 }, /* R1933 - AIF3TX2MIX Input 3 Volume */
- { 0x0000078E, 0x0000 }, /* R1934 - AIF3TX2MIX Input 4 Source */
- { 0x0000078F, 0x0080 }, /* R1935 - AIF3TX2MIX Input 4 Volume */
- { 0x000007C0, 0x0000 }, /* R1984 - SLIMTX1MIX Input 1 Source */
- { 0x000007C1, 0x0080 }, /* R1985 - SLIMTX1MIX Input 1 Volume */
- { 0x000007C2, 0x0000 }, /* R1986 - SLIMTX1MIX Input 2 Source */
- { 0x000007C3, 0x0080 }, /* R1987 - SLIMTX1MIX Input 2 Volume */
- { 0x000007C4, 0x0000 }, /* R1988 - SLIMTX1MIX Input 3 Source */
- { 0x000007C5, 0x0080 }, /* R1989 - SLIMTX1MIX Input 3 Volume */
- { 0x000007C6, 0x0000 }, /* R1990 - SLIMTX1MIX Input 4 Source */
- { 0x000007C7, 0x0080 }, /* R1991 - SLIMTX1MIX Input 4 Volume */
- { 0x000007C8, 0x0000 }, /* R1992 - SLIMTX2MIX Input 1 Source */
- { 0x000007C9, 0x0080 }, /* R1993 - SLIMTX2MIX Input 1 Volume */
- { 0x000007CA, 0x0000 }, /* R1994 - SLIMTX2MIX Input 2 Source */
- { 0x000007CB, 0x0080 }, /* R1995 - SLIMTX2MIX Input 2 Volume */
- { 0x000007CC, 0x0000 }, /* R1996 - SLIMTX2MIX Input 3 Source */
- { 0x000007CD, 0x0080 }, /* R1997 - SLIMTX2MIX Input 3 Volume */
- { 0x000007CE, 0x0000 }, /* R1998 - SLIMTX2MIX Input 4 Source */
- { 0x000007CF, 0x0080 }, /* R1999 - SLIMTX2MIX Input 4 Volume */
- { 0x000007D0, 0x0000 }, /* R2000 - SLIMTX3MIX Input 1 Source */
- { 0x000007D1, 0x0080 }, /* R2001 - SLIMTX3MIX Input 1 Volume */
- { 0x000007D2, 0x0000 }, /* R2002 - SLIMTX3MIX Input 2 Source */
- { 0x000007D3, 0x0080 }, /* R2003 - SLIMTX3MIX Input 2 Volume */
- { 0x000007D4, 0x0000 }, /* R2004 - SLIMTX3MIX Input 3 Source */
- { 0x000007D5, 0x0080 }, /* R2005 - SLIMTX3MIX Input 3 Volume */
- { 0x000007D6, 0x0000 }, /* R2006 - SLIMTX3MIX Input 4 Source */
- { 0x000007D7, 0x0080 }, /* R2007 - SLIMTX3MIX Input 4 Volume */
- { 0x000007D8, 0x0000 }, /* R2008 - SLIMTX4MIX Input 1 Source */
- { 0x000007D9, 0x0080 }, /* R2009 - SLIMTX4MIX Input 1 Volume */
- { 0x000007DA, 0x0000 }, /* R2010 - SLIMTX4MIX Input 2 Source */
- { 0x000007DB, 0x0080 }, /* R2011 - SLIMTX4MIX Input 2 Volume */
- { 0x000007DC, 0x0000 }, /* R2012 - SLIMTX4MIX Input 3 Source */
- { 0x000007DD, 0x0080 }, /* R2013 - SLIMTX4MIX Input 3 Volume */
- { 0x000007DE, 0x0000 }, /* R2014 - SLIMTX4MIX Input 4 Source */
- { 0x000007DF, 0x0080 }, /* R2015 - SLIMTX4MIX Input 4 Volume */
- { 0x000007E0, 0x0000 }, /* R2016 - SLIMTX5MIX Input 1 Source */
- { 0x000007E1, 0x0080 }, /* R2017 - SLIMTX5MIX Input 1 Volume */
- { 0x000007E2, 0x0000 }, /* R2018 - SLIMTX5MIX Input 2 Source */
- { 0x000007E3, 0x0080 }, /* R2019 - SLIMTX5MIX Input 2 Volume */
- { 0x000007E4, 0x0000 }, /* R2020 - SLIMTX5MIX Input 3 Source */
- { 0x000007E5, 0x0080 }, /* R2021 - SLIMTX5MIX Input 3 Volume */
- { 0x000007E6, 0x0000 }, /* R2022 - SLIMTX5MIX Input 4 Source */
- { 0x000007E7, 0x0080 }, /* R2023 - SLIMTX5MIX Input 4 Volume */
- { 0x000007E8, 0x0000 }, /* R2024 - SLIMTX6MIX Input 1 Source */
- { 0x000007E9, 0x0080 }, /* R2025 - SLIMTX6MIX Input 1 Volume */
- { 0x000007EA, 0x0000 }, /* R2026 - SLIMTX6MIX Input 2 Source */
- { 0x000007EB, 0x0080 }, /* R2027 - SLIMTX6MIX Input 2 Volume */
- { 0x000007EC, 0x0000 }, /* R2028 - SLIMTX6MIX Input 3 Source */
- { 0x000007ED, 0x0080 }, /* R2029 - SLIMTX6MIX Input 3 Volume */
- { 0x000007EE, 0x0000 }, /* R2030 - SLIMTX6MIX Input 4 Source */
- { 0x000007EF, 0x0080 }, /* R2031 - SLIMTX6MIX Input 4 Volume */
- { 0x000007F0, 0x0000 }, /* R2032 - SLIMTX7MIX Input 1 Source */
- { 0x000007F1, 0x0080 }, /* R2033 - SLIMTX7MIX Input 1 Volume */
- { 0x000007F2, 0x0000 }, /* R2034 - SLIMTX7MIX Input 2 Source */
- { 0x000007F3, 0x0080 }, /* R2035 - SLIMTX7MIX Input 2 Volume */
- { 0x000007F4, 0x0000 }, /* R2036 - SLIMTX7MIX Input 3 Source */
- { 0x000007F5, 0x0080 }, /* R2037 - SLIMTX7MIX Input 3 Volume */
- { 0x000007F6, 0x0000 }, /* R2038 - SLIMTX7MIX Input 4 Source */
- { 0x000007F7, 0x0080 }, /* R2039 - SLIMTX7MIX Input 4 Volume */
- { 0x000007F8, 0x0000 }, /* R2040 - SLIMTX8MIX Input 1 Source */
- { 0x000007F9, 0x0080 }, /* R2041 - SLIMTX8MIX Input 1 Volume */
- { 0x000007FA, 0x0000 }, /* R2042 - SLIMTX8MIX Input 2 Source */
- { 0x000007FB, 0x0080 }, /* R2043 - SLIMTX8MIX Input 2 Volume */
- { 0x000007FC, 0x0000 }, /* R2044 - SLIMTX8MIX Input 3 Source */
- { 0x000007FD, 0x0080 }, /* R2045 - SLIMTX8MIX Input 3 Volume */
- { 0x000007FE, 0x0000 }, /* R2046 - SLIMTX8MIX Input 4 Source */
- { 0x000007FF, 0x0080 }, /* R2047 - SLIMTX8MIX Input 4 Volume */
- { 0x00000880, 0x0000 }, /* R2176 - EQ1MIX Input 1 Source */
- { 0x00000881, 0x0080 }, /* R2177 - EQ1MIX Input 1 Volume */
- { 0x00000882, 0x0000 }, /* R2178 - EQ1MIX Input 2 Source */
- { 0x00000883, 0x0080 }, /* R2179 - EQ1MIX Input 2 Volume */
- { 0x00000884, 0x0000 }, /* R2180 - EQ1MIX Input 3 Source */
- { 0x00000885, 0x0080 }, /* R2181 - EQ1MIX Input 3 Volume */
- { 0x00000886, 0x0000 }, /* R2182 - EQ1MIX Input 4 Source */
- { 0x00000887, 0x0080 }, /* R2183 - EQ1MIX Input 4 Volume */
- { 0x00000888, 0x0000 }, /* R2184 - EQ2MIX Input 1 Source */
- { 0x00000889, 0x0080 }, /* R2185 - EQ2MIX Input 1 Volume */
- { 0x0000088A, 0x0000 }, /* R2186 - EQ2MIX Input 2 Source */
- { 0x0000088B, 0x0080 }, /* R2187 - EQ2MIX Input 2 Volume */
- { 0x0000088C, 0x0000 }, /* R2188 - EQ2MIX Input 3 Source */
- { 0x0000088D, 0x0080 }, /* R2189 - EQ2MIX Input 3 Volume */
- { 0x0000088E, 0x0000 }, /* R2190 - EQ2MIX Input 4 Source */
- { 0x0000088F, 0x0080 }, /* R2191 - EQ2MIX Input 4 Volume */
- { 0x00000890, 0x0000 }, /* R2192 - EQ3MIX Input 1 Source */
- { 0x00000891, 0x0080 }, /* R2193 - EQ3MIX Input 1 Volume */
- { 0x00000892, 0x0000 }, /* R2194 - EQ3MIX Input 2 Source */
- { 0x00000893, 0x0080 }, /* R2195 - EQ3MIX Input 2 Volume */
- { 0x00000894, 0x0000 }, /* R2196 - EQ3MIX Input 3 Source */
- { 0x00000895, 0x0080 }, /* R2197 - EQ3MIX Input 3 Volume */
- { 0x00000896, 0x0000 }, /* R2198 - EQ3MIX Input 4 Source */
- { 0x00000897, 0x0080 }, /* R2199 - EQ3MIX Input 4 Volume */
- { 0x00000898, 0x0000 }, /* R2200 - EQ4MIX Input 1 Source */
- { 0x00000899, 0x0080 }, /* R2201 - EQ4MIX Input 1 Volume */
- { 0x0000089A, 0x0000 }, /* R2202 - EQ4MIX Input 2 Source */
- { 0x0000089B, 0x0080 }, /* R2203 - EQ4MIX Input 2 Volume */
- { 0x0000089C, 0x0000 }, /* R2204 - EQ4MIX Input 3 Source */
- { 0x0000089D, 0x0080 }, /* R2205 - EQ4MIX Input 3 Volume */
- { 0x0000089E, 0x0000 }, /* R2206 - EQ4MIX Input 4 Source */
- { 0x0000089F, 0x0080 }, /* R2207 - EQ4MIX Input 4 Volume */
- { 0x000008C0, 0x0000 }, /* R2240 - DRC1LMIX Input 1 Source */
- { 0x000008C1, 0x0080 }, /* R2241 - DRC1LMIX Input 1 Volume */
- { 0x000008C2, 0x0000 }, /* R2242 - DRC1LMIX Input 2 Source */
- { 0x000008C3, 0x0080 }, /* R2243 - DRC1LMIX Input 2 Volume */
- { 0x000008C4, 0x0000 }, /* R2244 - DRC1LMIX Input 3 Source */
- { 0x000008C5, 0x0080 }, /* R2245 - DRC1LMIX Input 3 Volume */
- { 0x000008C6, 0x0000 }, /* R2246 - DRC1LMIX Input 4 Source */
- { 0x000008C7, 0x0080 }, /* R2247 - DRC1LMIX Input 4 Volume */
- { 0x000008C8, 0x0000 }, /* R2248 - DRC1RMIX Input 1 Source */
- { 0x000008C9, 0x0080 }, /* R2249 - DRC1RMIX Input 1 Volume */
- { 0x000008CA, 0x0000 }, /* R2250 - DRC1RMIX Input 2 Source */
- { 0x000008CB, 0x0080 }, /* R2251 - DRC1RMIX Input 2 Volume */
- { 0x000008CC, 0x0000 }, /* R2252 - DRC1RMIX Input 3 Source */
- { 0x000008CD, 0x0080 }, /* R2253 - DRC1RMIX Input 3 Volume */
- { 0x000008CE, 0x0000 }, /* R2254 - DRC1RMIX Input 4 Source */
- { 0x000008CF, 0x0080 }, /* R2255 - DRC1RMIX Input 4 Volume */
- { 0x00000900, 0x0000 }, /* R2304 - HPLP1MIX Input 1 Source */
- { 0x00000901, 0x0080 }, /* R2305 - HPLP1MIX Input 1 Volume */
- { 0x00000902, 0x0000 }, /* R2306 - HPLP1MIX Input 2 Source */
- { 0x00000903, 0x0080 }, /* R2307 - HPLP1MIX Input 2 Volume */
- { 0x00000904, 0x0000 }, /* R2308 - HPLP1MIX Input 3 Source */
- { 0x00000905, 0x0080 }, /* R2309 - HPLP1MIX Input 3 Volume */
- { 0x00000906, 0x0000 }, /* R2310 - HPLP1MIX Input 4 Source */
- { 0x00000907, 0x0080 }, /* R2311 - HPLP1MIX Input 4 Volume */
- { 0x00000908, 0x0000 }, /* R2312 - HPLP2MIX Input 1 Source */
- { 0x00000909, 0x0080 }, /* R2313 - HPLP2MIX Input 1 Volume */
- { 0x0000090A, 0x0000 }, /* R2314 - HPLP2MIX Input 2 Source */
- { 0x0000090B, 0x0080 }, /* R2315 - HPLP2MIX Input 2 Volume */
- { 0x0000090C, 0x0000 }, /* R2316 - HPLP2MIX Input 3 Source */
- { 0x0000090D, 0x0080 }, /* R2317 - HPLP2MIX Input 3 Volume */
- { 0x0000090E, 0x0000 }, /* R2318 - HPLP2MIX Input 4 Source */
- { 0x0000090F, 0x0080 }, /* R2319 - HPLP2MIX Input 4 Volume */
- { 0x00000910, 0x0000 }, /* R2320 - HPLP3MIX Input 1 Source */
- { 0x00000911, 0x0080 }, /* R2321 - HPLP3MIX Input 1 Volume */
- { 0x00000912, 0x0000 }, /* R2322 - HPLP3MIX Input 2 Source */
- { 0x00000913, 0x0080 }, /* R2323 - HPLP3MIX Input 2 Volume */
- { 0x00000914, 0x0000 }, /* R2324 - HPLP3MIX Input 3 Source */
- { 0x00000915, 0x0080 }, /* R2325 - HPLP3MIX Input 3 Volume */
- { 0x00000916, 0x0000 }, /* R2326 - HPLP3MIX Input 4 Source */
- { 0x00000917, 0x0080 }, /* R2327 - HPLP3MIX Input 4 Volume */
- { 0x00000918, 0x0000 }, /* R2328 - HPLP4MIX Input 1 Source */
- { 0x00000919, 0x0080 }, /* R2329 - HPLP4MIX Input 1 Volume */
- { 0x0000091A, 0x0000 }, /* R2330 - HPLP4MIX Input 2 Source */
- { 0x0000091B, 0x0080 }, /* R2331 - HPLP4MIX Input 2 Volume */
- { 0x0000091C, 0x0000 }, /* R2332 - HPLP4MIX Input 3 Source */
- { 0x0000091D, 0x0080 }, /* R2333 - HPLP4MIX Input 3 Volume */
- { 0x0000091E, 0x0000 }, /* R2334 - HPLP4MIX Input 4 Source */
- { 0x0000091F, 0x0080 }, /* R2335 - HPLP4MIX Input 4 Volume */
- { 0x00000940, 0x0000 }, /* R2368 - DSP1LMIX Input 1 Source */
- { 0x00000941, 0x0080 }, /* R2369 - DSP1LMIX Input 1 Volume */
- { 0x00000942, 0x0000 }, /* R2370 - DSP1LMIX Input 2 Source */
- { 0x00000943, 0x0080 }, /* R2371 - DSP1LMIX Input 2 Volume */
- { 0x00000944, 0x0000 }, /* R2372 - DSP1LMIX Input 3 Source */
- { 0x00000945, 0x0080 }, /* R2373 - DSP1LMIX Input 3 Volume */
- { 0x00000946, 0x0000 }, /* R2374 - DSP1LMIX Input 4 Source */
- { 0x00000947, 0x0080 }, /* R2375 - DSP1LMIX Input 4 Volume */
- { 0x00000948, 0x0000 }, /* R2376 - DSP1RMIX Input 1 Source */
- { 0x00000949, 0x0080 }, /* R2377 - DSP1RMIX Input 1 Volume */
- { 0x0000094A, 0x0000 }, /* R2378 - DSP1RMIX Input 2 Source */
- { 0x0000094B, 0x0080 }, /* R2379 - DSP1RMIX Input 2 Volume */
- { 0x0000094C, 0x0000 }, /* R2380 - DSP1RMIX Input 3 Source */
- { 0x0000094D, 0x0080 }, /* R2381 - DSP1RMIX Input 3 Volume */
- { 0x0000094E, 0x0000 }, /* R2382 - DSP1RMIX Input 4 Source */
- { 0x0000094F, 0x0080 }, /* R2383 - DSP1RMIX Input 4 Volume */
- { 0x00000950, 0x0000 }, /* R2384 - DSP1AUX1MIX Input 1 Source */
- { 0x00000958, 0x0000 }, /* R2392 - DSP1AUX2MIX Input 1 Source */
- { 0x00000960, 0x0000 }, /* R2400 - DSP1AUX3MIX Input 1 Source */
- { 0x00000968, 0x0000 }, /* R2408 - DSP1AUX4MIX Input 1 Source */
- { 0x00000970, 0x0000 }, /* R2416 - DSP1AUX5MIX Input 1 Source */
- { 0x00000978, 0x0000 }, /* R2424 - DSP1AUX6MIX Input 1 Source */
- { 0x00000A80, 0x0000 }, /* R2688 - ASRC1LMIX Input 1 Source */
- { 0x00000A88, 0x0000 }, /* R2696 - ASRC1RMIX Input 1 Source */
- { 0x00000A90, 0x0000 }, /* R2704 - ASRC2LMIX Input 1 Source */
- { 0x00000A98, 0x0000 }, /* R2712 - ASRC2RMIX Input 1 Source */
- { 0x00000B00, 0x0000 }, /* R2816 - ISRC1DEC1MIX Input 1 Source */
- { 0x00000B08, 0x0000 }, /* R2824 - ISRC1DEC2MIX Input 1 Source */
- { 0x00000B20, 0x0000 }, /* R2848 - ISRC1INT1MIX Input 1 Source */
- { 0x00000B28, 0x0000 }, /* R2856 - ISRC1INT2MIX Input 1 Source */
- { 0x00000B40, 0x0000 }, /* R2880 - ISRC2DEC1MIX Input 1 Source */
- { 0x00000B48, 0x0000 }, /* R2888 - ISRC2DEC2MIX Input 1 Source */
- { 0x00000B60, 0x0000 }, /* R2912 - ISRC2INT1MIX Input 1 Source */
- { 0x00000B68, 0x0000 }, /* R2920 - ISRC2INT2MIX Input 1 Source */
- { 0x00000C00, 0xA101 }, /* R3072 - GPIO1 CTRL */
- { 0x00000C01, 0xA101 }, /* R3073 - GPIO2 CTRL */
- { 0x00000C02, 0xA101 }, /* R3074 - GPIO3 CTRL */
- { 0x00000C03, 0xA101 }, /* R3075 - GPIO4 CTRL */
- { 0x00000C04, 0xA101 }, /* R3076 - GPIO5 CTRL */
- { 0x00000C0F, 0x0400 }, /* R3087 - IRQ CTRL 1 */
- { 0x00000C10, 0x1000 }, /* R3088 - GPIO Debounce Config */
- { 0x00000C20, 0x8002 }, /* R3104 - Misc Pad Ctrl 1 */
+ { 0x00000490, 0x0069 }, /* R1168 - PDM SPK1 CTRL 1 */
+ { 0x00000491, 0x0000 }, /* R1169 - PDM SPK1 CTRL 2 */
+ { 0x00000500, 0x000C }, /* R1280 - AIF1 BCLK Ctrl */
+ { 0x00000501, 0x0008 }, /* R1281 - AIF1 Tx Pin Ctrl */
+ { 0x00000502, 0x0000 }, /* R1282 - AIF1 Rx Pin Ctrl */
+ { 0x00000503, 0x0000 }, /* R1283 - AIF1 Rate Ctrl */
+ { 0x00000504, 0x0000 }, /* R1284 - AIF1 Format */
+ { 0x00000505, 0x0040 }, /* R1285 - AIF1 Tx BCLK Rate */
+ { 0x00000506, 0x0040 }, /* R1286 - AIF1 Rx BCLK Rate */
+ { 0x00000507, 0x1818 }, /* R1287 - AIF1 Frame Ctrl 1 */
+ { 0x00000508, 0x1818 }, /* R1288 - AIF1 Frame Ctrl 2 */
+ { 0x00000509, 0x0000 }, /* R1289 - AIF1 Frame Ctrl 3 */
+ { 0x0000050A, 0x0001 }, /* R1290 - AIF1 Frame Ctrl 4 */
+ { 0x0000050B, 0x0002 }, /* R1291 - AIF1 Frame Ctrl 5 */
+ { 0x0000050C, 0x0003 }, /* R1292 - AIF1 Frame Ctrl 6 */
+ { 0x0000050D, 0x0004 }, /* R1293 - AIF1 Frame Ctrl 7 */
+ { 0x0000050E, 0x0005 }, /* R1294 - AIF1 Frame Ctrl 8 */
+ { 0x0000050F, 0x0006 }, /* R1295 - AIF1 Frame Ctrl 9 */
+ { 0x00000510, 0x0007 }, /* R1296 - AIF1 Frame Ctrl 10 */
+ { 0x00000511, 0x0000 }, /* R1297 - AIF1 Frame Ctrl 11 */
+ { 0x00000512, 0x0001 }, /* R1298 - AIF1 Frame Ctrl 12 */
+ { 0x00000513, 0x0002 }, /* R1299 - AIF1 Frame Ctrl 13 */
+ { 0x00000514, 0x0003 }, /* R1300 - AIF1 Frame Ctrl 14 */
+ { 0x00000515, 0x0004 }, /* R1301 - AIF1 Frame Ctrl 15 */
+ { 0x00000516, 0x0005 }, /* R1302 - AIF1 Frame Ctrl 16 */
+ { 0x00000517, 0x0006 }, /* R1303 - AIF1 Frame Ctrl 17 */
+ { 0x00000518, 0x0007 }, /* R1304 - AIF1 Frame Ctrl 18 */
+ { 0x00000519, 0x0000 }, /* R1305 - AIF1 Tx Enables */
+ { 0x0000051A, 0x0000 }, /* R1306 - AIF1 Rx Enables */
+ { 0x00000540, 0x000C }, /* R1344 - AIF2 BCLK Ctrl */
+ { 0x00000541, 0x0008 }, /* R1345 - AIF2 Tx Pin Ctrl */
+ { 0x00000542, 0x0000 }, /* R1346 - AIF2 Rx Pin Ctrl */
+ { 0x00000543, 0x0000 }, /* R1347 - AIF2 Rate Ctrl */
+ { 0x00000544, 0x0000 }, /* R1348 - AIF2 Format */
+ { 0x00000545, 0x0040 }, /* R1349 - AIF2 Tx BCLK Rate */
+ { 0x00000546, 0x0040 }, /* R1350 - AIF2 Rx BCLK Rate */
+ { 0x00000547, 0x1818 }, /* R1351 - AIF2 Frame Ctrl 1 */
+ { 0x00000548, 0x1818 }, /* R1352 - AIF2 Frame Ctrl 2 */
+ { 0x00000549, 0x0000 }, /* R1353 - AIF2 Frame Ctrl 3 */
+ { 0x0000054A, 0x0001 }, /* R1354 - AIF2 Frame Ctrl 4 */
+ { 0x00000551, 0x0000 }, /* R1361 - AIF2 Frame Ctrl 11 */
+ { 0x00000552, 0x0001 }, /* R1362 - AIF2 Frame Ctrl 12 */
+ { 0x00000559, 0x0000 }, /* R1369 - AIF2 Tx Enables */
+ { 0x0000055A, 0x0000 }, /* R1370 - AIF2 Rx Enables */
+ { 0x00000580, 0x000C }, /* R1408 - AIF3 BCLK Ctrl */
+ { 0x00000581, 0x0008 }, /* R1409 - AIF3 Tx Pin Ctrl */
+ { 0x00000582, 0x0000 }, /* R1410 - AIF3 Rx Pin Ctrl */
+ { 0x00000583, 0x0000 }, /* R1411 - AIF3 Rate Ctrl */
+ { 0x00000584, 0x0000 }, /* R1412 - AIF3 Format */
+ { 0x00000585, 0x0040 }, /* R1413 - AIF3 Tx BCLK Rate */
+ { 0x00000586, 0x0040 }, /* R1414 - AIF3 Rx BCLK Rate */
+ { 0x00000587, 0x1818 }, /* R1415 - AIF3 Frame Ctrl 1 */
+ { 0x00000588, 0x1818 }, /* R1416 - AIF3 Frame Ctrl 2 */
+ { 0x00000589, 0x0000 }, /* R1417 - AIF3 Frame Ctrl 3 */
+ { 0x0000058A, 0x0001 }, /* R1418 - AIF3 Frame Ctrl 4 */
+ { 0x00000591, 0x0000 }, /* R1425 - AIF3 Frame Ctrl 11 */
+ { 0x00000592, 0x0001 }, /* R1426 - AIF3 Frame Ctrl 12 */
+ { 0x00000599, 0x0000 }, /* R1433 - AIF3 Tx Enables */
+ { 0x0000059A, 0x0000 }, /* R1434 - AIF3 Rx Enables */
+ { 0x000005E3, 0x0004 }, /* R1507 - SLIMbus Framer Ref Gear */
+ { 0x000005E5, 0x0000 }, /* R1509 - SLIMbus Rates 1 */
+ { 0x000005E6, 0x0000 }, /* R1510 - SLIMbus Rates 2 */
+ { 0x000005E7, 0x0000 }, /* R1511 - SLIMbus Rates 3 */
+ { 0x000005E8, 0x0000 }, /* R1512 - SLIMbus Rates 4 */
+ { 0x000005E9, 0x0000 }, /* R1513 - SLIMbus Rates 5 */
+ { 0x000005EA, 0x0000 }, /* R1514 - SLIMbus Rates 6 */
+ { 0x000005EB, 0x0000 }, /* R1515 - SLIMbus Rates 7 */
+ { 0x000005EC, 0x0000 }, /* R1516 - SLIMbus Rates 8 */
+ { 0x000005F5, 0x0000 }, /* R1525 - SLIMbus RX Channel Enable */
+ { 0x000005F6, 0x0000 }, /* R1526 - SLIMbus TX Channel Enable */
+ { 0x00000640, 0x0000 }, /* R1600 - PWM1MIX Input 1 Source */
+ { 0x00000641, 0x0080 }, /* R1601 - PWM1MIX Input 1 Volume */
+ { 0x00000642, 0x0000 }, /* R1602 - PWM1MIX Input 2 Source */
+ { 0x00000643, 0x0080 }, /* R1603 - PWM1MIX Input 2 Volume */
+ { 0x00000644, 0x0000 }, /* R1604 - PWM1MIX Input 3 Source */
+ { 0x00000645, 0x0080 }, /* R1605 - PWM1MIX Input 3 Volume */
+ { 0x00000646, 0x0000 }, /* R1606 - PWM1MIX Input 4 Source */
+ { 0x00000647, 0x0080 }, /* R1607 - PWM1MIX Input 4 Volume */
+ { 0x00000648, 0x0000 }, /* R1608 - PWM2MIX Input 1 Source */
+ { 0x00000649, 0x0080 }, /* R1609 - PWM2MIX Input 1 Volume */
+ { 0x0000064A, 0x0000 }, /* R1610 - PWM2MIX Input 2 Source */
+ { 0x0000064B, 0x0080 }, /* R1611 - PWM2MIX Input 2 Volume */
+ { 0x0000064C, 0x0000 }, /* R1612 - PWM2MIX Input 3 Source */
+ { 0x0000064D, 0x0080 }, /* R1613 - PWM2MIX Input 3 Volume */
+ { 0x0000064E, 0x0000 }, /* R1614 - PWM2MIX Input 4 Source */
+ { 0x0000064F, 0x0080 }, /* R1615 - PWM2MIX Input 4 Volume */
+ { 0x00000660, 0x0000 }, /* R1632 - MICMIX Input 1 Source */
+ { 0x00000661, 0x0080 }, /* R1633 - MICMIX Input 1 Volume */
+ { 0x00000662, 0x0000 }, /* R1634 - MICMIX Input 2 Source */
+ { 0x00000663, 0x0080 }, /* R1635 - MICMIX Input 2 Volume */
+ { 0x00000664, 0x0000 }, /* R1636 - MICMIX Input 3 Source */
+ { 0x00000665, 0x0080 }, /* R1637 - MICMIX Input 3 Volume */
+ { 0x00000666, 0x0000 }, /* R1638 - MICMIX Input 4 Source */
+ { 0x00000667, 0x0080 }, /* R1639 - MICMIX Input 4 Volume */
+ { 0x00000668, 0x0000 }, /* R1640 - NOISEMIX Input 1 Source */
+ { 0x00000669, 0x0080 }, /* R1641 - NOISEMIX Input 1 Volume */
+ { 0x0000066A, 0x0000 }, /* R1642 - NOISEMIX Input 2 Source */
+ { 0x0000066B, 0x0080 }, /* R1643 - NOISEMIX Input 2 Volume */
+ { 0x0000066C, 0x0000 }, /* R1644 - NOISEMIX Input 3 Source */
+ { 0x0000066D, 0x0080 }, /* R1645 - NOISEMIX Input 3 Volume */
+ { 0x0000066E, 0x0000 }, /* R1646 - NOISEMIX Input 4 Source */
+ { 0x0000066F, 0x0080 }, /* R1647 - NOISEMIX Input 4 Volume */
+ { 0x00000680, 0x0000 }, /* R1664 - OUT1LMIX Input 1 Source */
+ { 0x00000681, 0x0080 }, /* R1665 - OUT1LMIX Input 1 Volume */
+ { 0x00000682, 0x0000 }, /* R1666 - OUT1LMIX Input 2 Source */
+ { 0x00000683, 0x0080 }, /* R1667 - OUT1LMIX Input 2 Volume */
+ { 0x00000684, 0x0000 }, /* R1668 - OUT1LMIX Input 3 Source */
+ { 0x00000685, 0x0080 }, /* R1669 - OUT1LMIX Input 3 Volume */
+ { 0x00000686, 0x0000 }, /* R1670 - OUT1LMIX Input 4 Source */
+ { 0x00000687, 0x0080 }, /* R1671 - OUT1LMIX Input 4 Volume */
+ { 0x00000688, 0x0000 }, /* R1672 - OUT1RMIX Input 1 Source */
+ { 0x00000689, 0x0080 }, /* R1673 - OUT1RMIX Input 1 Volume */
+ { 0x0000068A, 0x0000 }, /* R1674 - OUT1RMIX Input 2 Source */
+ { 0x0000068B, 0x0080 }, /* R1675 - OUT1RMIX Input 2 Volume */
+ { 0x0000068C, 0x0000 }, /* R1676 - OUT1RMIX Input 3 Source */
+ { 0x0000068D, 0x0080 }, /* R1677 - OUT1RMIX Input 3 Volume */
+ { 0x0000068E, 0x0000 }, /* R1678 - OUT1RMIX Input 4 Source */
+ { 0x0000068F, 0x0080 }, /* R1679 - OUT1RMIX Input 4 Volume */
+ { 0x00000690, 0x0000 }, /* R1680 - OUT2LMIX Input 1 Source */
+ { 0x00000691, 0x0080 }, /* R1681 - OUT2LMIX Input 1 Volume */
+ { 0x00000692, 0x0000 }, /* R1682 - OUT2LMIX Input 2 Source */
+ { 0x00000693, 0x0080 }, /* R1683 - OUT2LMIX Input 2 Volume */
+ { 0x00000694, 0x0000 }, /* R1684 - OUT2LMIX Input 3 Source */
+ { 0x00000695, 0x0080 }, /* R1685 - OUT2LMIX Input 3 Volume */
+ { 0x00000696, 0x0000 }, /* R1686 - OUT2LMIX Input 4 Source */
+ { 0x00000697, 0x0080 }, /* R1687 - OUT2LMIX Input 4 Volume */
+ { 0x00000698, 0x0000 }, /* R1688 - OUT2RMIX Input 1 Source */
+ { 0x00000699, 0x0080 }, /* R1689 - OUT2RMIX Input 1 Volume */
+ { 0x0000069A, 0x0000 }, /* R1690 - OUT2RMIX Input 2 Source */
+ { 0x0000069B, 0x0080 }, /* R1691 - OUT2RMIX Input 2 Volume */
+ { 0x0000069C, 0x0000 }, /* R1692 - OUT2RMIX Input 3 Source */
+ { 0x0000069D, 0x0080 }, /* R1693 - OUT2RMIX Input 3 Volume */
+ { 0x0000069E, 0x0000 }, /* R1694 - OUT2RMIX Input 4 Source */
+ { 0x0000069F, 0x0080 }, /* R1695 - OUT2RMIX Input 4 Volume */
+ { 0x000006A0, 0x0000 }, /* R1696 - OUT3LMIX Input 1 Source */
+ { 0x000006A1, 0x0080 }, /* R1697 - OUT3LMIX Input 1 Volume */
+ { 0x000006A2, 0x0000 }, /* R1698 - OUT3LMIX Input 2 Source */
+ { 0x000006A3, 0x0080 }, /* R1699 - OUT3LMIX Input 2 Volume */
+ { 0x000006A4, 0x0000 }, /* R1700 - OUT3LMIX Input 3 Source */
+ { 0x000006A5, 0x0080 }, /* R1701 - OUT3LMIX Input 3 Volume */
+ { 0x000006A6, 0x0000 }, /* R1702 - OUT3LMIX Input 4 Source */
+ { 0x000006A7, 0x0080 }, /* R1703 - OUT3LMIX Input 4 Volume */
+ { 0x000006B0, 0x0000 }, /* R1712 - OUT4LMIX Input 1 Source */
+ { 0x000006B1, 0x0080 }, /* R1713 - OUT4LMIX Input 1 Volume */
+ { 0x000006B2, 0x0000 }, /* R1714 - OUT4LMIX Input 2 Source */
+ { 0x000006B3, 0x0080 }, /* R1715 - OUT4LMIX Input 2 Volume */
+ { 0x000006B4, 0x0000 }, /* R1716 - OUT4LMIX Input 3 Source */
+ { 0x000006B5, 0x0080 }, /* R1717 - OUT4LMIX Input 3 Volume */
+ { 0x000006B6, 0x0000 }, /* R1718 - OUT4LMIX Input 4 Source */
+ { 0x000006B7, 0x0080 }, /* R1719 - OUT4LMIX Input 4 Volume */
+ { 0x000006B8, 0x0000 }, /* R1720 - OUT4RMIX Input 1 Source */
+ { 0x000006B9, 0x0080 }, /* R1721 - OUT4RMIX Input 1 Volume */
+ { 0x000006BA, 0x0000 }, /* R1722 - OUT4RMIX Input 2 Source */
+ { 0x000006BB, 0x0080 }, /* R1723 - OUT4RMIX Input 2 Volume */
+ { 0x000006BC, 0x0000 }, /* R1724 - OUT4RMIX Input 3 Source */
+ { 0x000006BD, 0x0080 }, /* R1725 - OUT4RMIX Input 3 Volume */
+ { 0x000006BE, 0x0000 }, /* R1726 - OUT4RMIX Input 4 Source */
+ { 0x000006BF, 0x0080 }, /* R1727 - OUT4RMIX Input 4 Volume */
+ { 0x000006C0, 0x0000 }, /* R1728 - OUT5LMIX Input 1 Source */
+ { 0x000006C1, 0x0080 }, /* R1729 - OUT5LMIX Input 1 Volume */
+ { 0x000006C2, 0x0000 }, /* R1730 - OUT5LMIX Input 2 Source */
+ { 0x000006C3, 0x0080 }, /* R1731 - OUT5LMIX Input 2 Volume */
+ { 0x000006C4, 0x0000 }, /* R1732 - OUT5LMIX Input 3 Source */
+ { 0x000006C5, 0x0080 }, /* R1733 - OUT5LMIX Input 3 Volume */
+ { 0x000006C6, 0x0000 }, /* R1734 - OUT5LMIX Input 4 Source */
+ { 0x000006C7, 0x0080 }, /* R1735 - OUT5LMIX Input 4 Volume */
+ { 0x000006C8, 0x0000 }, /* R1736 - OUT5RMIX Input 1 Source */
+ { 0x000006C9, 0x0080 }, /* R1737 - OUT5RMIX Input 1 Volume */
+ { 0x000006CA, 0x0000 }, /* R1738 - OUT5RMIX Input 2 Source */
+ { 0x000006CB, 0x0080 }, /* R1739 - OUT5RMIX Input 2 Volume */
+ { 0x000006CC, 0x0000 }, /* R1740 - OUT5RMIX Input 3 Source */
+ { 0x000006CD, 0x0080 }, /* R1741 - OUT5RMIX Input 3 Volume */
+ { 0x000006CE, 0x0000 }, /* R1742 - OUT5RMIX Input 4 Source */
+ { 0x000006CF, 0x0080 }, /* R1743 - OUT5RMIX Input 4 Volume */
+ { 0x00000700, 0x0000 }, /* R1792 - AIF1TX1MIX Input 1 Source */
+ { 0x00000701, 0x0080 }, /* R1793 - AIF1TX1MIX Input 1 Volume */
+ { 0x00000702, 0x0000 }, /* R1794 - AIF1TX1MIX Input 2 Source */
+ { 0x00000703, 0x0080 }, /* R1795 - AIF1TX1MIX Input 2 Volume */
+ { 0x00000704, 0x0000 }, /* R1796 - AIF1TX1MIX Input 3 Source */
+ { 0x00000705, 0x0080 }, /* R1797 - AIF1TX1MIX Input 3 Volume */
+ { 0x00000706, 0x0000 }, /* R1798 - AIF1TX1MIX Input 4 Source */
+ { 0x00000707, 0x0080 }, /* R1799 - AIF1TX1MIX Input 4 Volume */
+ { 0x00000708, 0x0000 }, /* R1800 - AIF1TX2MIX Input 1 Source */
+ { 0x00000709, 0x0080 }, /* R1801 - AIF1TX2MIX Input 1 Volume */
+ { 0x0000070A, 0x0000 }, /* R1802 - AIF1TX2MIX Input 2 Source */
+ { 0x0000070B, 0x0080 }, /* R1803 - AIF1TX2MIX Input 2 Volume */
+ { 0x0000070C, 0x0000 }, /* R1804 - AIF1TX2MIX Input 3 Source */
+ { 0x0000070D, 0x0080 }, /* R1805 - AIF1TX2MIX Input 3 Volume */
+ { 0x0000070E, 0x0000 }, /* R1806 - AIF1TX2MIX Input 4 Source */
+ { 0x0000070F, 0x0080 }, /* R1807 - AIF1TX2MIX Input 4 Volume */
+ { 0x00000710, 0x0000 }, /* R1808 - AIF1TX3MIX Input 1 Source */
+ { 0x00000711, 0x0080 }, /* R1809 - AIF1TX3MIX Input 1 Volume */
+ { 0x00000712, 0x0000 }, /* R1810 - AIF1TX3MIX Input 2 Source */
+ { 0x00000713, 0x0080 }, /* R1811 - AIF1TX3MIX Input 2 Volume */
+ { 0x00000714, 0x0000 }, /* R1812 - AIF1TX3MIX Input 3 Source */
+ { 0x00000715, 0x0080 }, /* R1813 - AIF1TX3MIX Input 3 Volume */
+ { 0x00000716, 0x0000 }, /* R1814 - AIF1TX3MIX Input 4 Source */
+ { 0x00000717, 0x0080 }, /* R1815 - AIF1TX3MIX Input 4 Volume */
+ { 0x00000718, 0x0000 }, /* R1816 - AIF1TX4MIX Input 1 Source */
+ { 0x00000719, 0x0080 }, /* R1817 - AIF1TX4MIX Input 1 Volume */
+ { 0x0000071A, 0x0000 }, /* R1818 - AIF1TX4MIX Input 2 Source */
+ { 0x0000071B, 0x0080 }, /* R1819 - AIF1TX4MIX Input 2 Volume */
+ { 0x0000071C, 0x0000 }, /* R1820 - AIF1TX4MIX Input 3 Source */
+ { 0x0000071D, 0x0080 }, /* R1821 - AIF1TX4MIX Input 3 Volume */
+ { 0x0000071E, 0x0000 }, /* R1822 - AIF1TX4MIX Input 4 Source */
+ { 0x0000071F, 0x0080 }, /* R1823 - AIF1TX4MIX Input 4 Volume */
+ { 0x00000720, 0x0000 }, /* R1824 - AIF1TX5MIX Input 1 Source */
+ { 0x00000721, 0x0080 }, /* R1825 - AIF1TX5MIX Input 1 Volume */
+ { 0x00000722, 0x0000 }, /* R1826 - AIF1TX5MIX Input 2 Source */
+ { 0x00000723, 0x0080 }, /* R1827 - AIF1TX5MIX Input 2 Volume */
+ { 0x00000724, 0x0000 }, /* R1828 - AIF1TX5MIX Input 3 Source */
+ { 0x00000725, 0x0080 }, /* R1829 - AIF1TX5MIX Input 3 Volume */
+ { 0x00000726, 0x0000 }, /* R1830 - AIF1TX5MIX Input 4 Source */
+ { 0x00000727, 0x0080 }, /* R1831 - AIF1TX5MIX Input 4 Volume */
+ { 0x00000728, 0x0000 }, /* R1832 - AIF1TX6MIX Input 1 Source */
+ { 0x00000729, 0x0080 }, /* R1833 - AIF1TX6MIX Input 1 Volume */
+ { 0x0000072A, 0x0000 }, /* R1834 - AIF1TX6MIX Input 2 Source */
+ { 0x0000072B, 0x0080 }, /* R1835 - AIF1TX6MIX Input 2 Volume */
+ { 0x0000072C, 0x0000 }, /* R1836 - AIF1TX6MIX Input 3 Source */
+ { 0x0000072D, 0x0080 }, /* R1837 - AIF1TX6MIX Input 3 Volume */
+ { 0x0000072E, 0x0000 }, /* R1838 - AIF1TX6MIX Input 4 Source */
+ { 0x0000072F, 0x0080 }, /* R1839 - AIF1TX6MIX Input 4 Volume */
+ { 0x00000730, 0x0000 }, /* R1840 - AIF1TX7MIX Input 1 Source */
+ { 0x00000731, 0x0080 }, /* R1841 - AIF1TX7MIX Input 1 Volume */
+ { 0x00000732, 0x0000 }, /* R1842 - AIF1TX7MIX Input 2 Source */
+ { 0x00000733, 0x0080 }, /* R1843 - AIF1TX7MIX Input 2 Volume */
+ { 0x00000734, 0x0000 }, /* R1844 - AIF1TX7MIX Input 3 Source */
+ { 0x00000735, 0x0080 }, /* R1845 - AIF1TX7MIX Input 3 Volume */
+ { 0x00000736, 0x0000 }, /* R1846 - AIF1TX7MIX Input 4 Source */
+ { 0x00000737, 0x0080 }, /* R1847 - AIF1TX7MIX Input 4 Volume */
+ { 0x00000738, 0x0000 }, /* R1848 - AIF1TX8MIX Input 1 Source */
+ { 0x00000739, 0x0080 }, /* R1849 - AIF1TX8MIX Input 1 Volume */
+ { 0x0000073A, 0x0000 }, /* R1850 - AIF1TX8MIX Input 2 Source */
+ { 0x0000073B, 0x0080 }, /* R1851 - AIF1TX8MIX Input 2 Volume */
+ { 0x0000073C, 0x0000 }, /* R1852 - AIF1TX8MIX Input 3 Source */
+ { 0x0000073D, 0x0080 }, /* R1853 - AIF1TX8MIX Input 3 Volume */
+ { 0x0000073E, 0x0000 }, /* R1854 - AIF1TX8MIX Input 4 Source */
+ { 0x0000073F, 0x0080 }, /* R1855 - AIF1TX8MIX Input 4 Volume */
+ { 0x00000740, 0x0000 }, /* R1856 - AIF2TX1MIX Input 1 Source */
+ { 0x00000741, 0x0080 }, /* R1857 - AIF2TX1MIX Input 1 Volume */
+ { 0x00000742, 0x0000 }, /* R1858 - AIF2TX1MIX Input 2 Source */
+ { 0x00000743, 0x0080 }, /* R1859 - AIF2TX1MIX Input 2 Volume */
+ { 0x00000744, 0x0000 }, /* R1860 - AIF2TX1MIX Input 3 Source */
+ { 0x00000745, 0x0080 }, /* R1861 - AIF2TX1MIX Input 3 Volume */
+ { 0x00000746, 0x0000 }, /* R1862 - AIF2TX1MIX Input 4 Source */
+ { 0x00000747, 0x0080 }, /* R1863 - AIF2TX1MIX Input 4 Volume */
+ { 0x00000748, 0x0000 }, /* R1864 - AIF2TX2MIX Input 1 Source */
+ { 0x00000749, 0x0080 }, /* R1865 - AIF2TX2MIX Input 1 Volume */
+ { 0x0000074A, 0x0000 }, /* R1866 - AIF2TX2MIX Input 2 Source */
+ { 0x0000074B, 0x0080 }, /* R1867 - AIF2TX2MIX Input 2 Volume */
+ { 0x0000074C, 0x0000 }, /* R1868 - AIF2TX2MIX Input 3 Source */
+ { 0x0000074D, 0x0080 }, /* R1869 - AIF2TX2MIX Input 3 Volume */
+ { 0x0000074E, 0x0000 }, /* R1870 - AIF2TX2MIX Input 4 Source */
+ { 0x0000074F, 0x0080 }, /* R1871 - AIF2TX2MIX Input 4 Volume */
+ { 0x00000780, 0x0000 }, /* R1920 - AIF3TX1MIX Input 1 Source */
+ { 0x00000781, 0x0080 }, /* R1921 - AIF3TX1MIX Input 1 Volume */
+ { 0x00000782, 0x0000 }, /* R1922 - AIF3TX1MIX Input 2 Source */
+ { 0x00000783, 0x0080 }, /* R1923 - AIF3TX1MIX Input 2 Volume */
+ { 0x00000784, 0x0000 }, /* R1924 - AIF3TX1MIX Input 3 Source */
+ { 0x00000785, 0x0080 }, /* R1925 - AIF3TX1MIX Input 3 Volume */
+ { 0x00000786, 0x0000 }, /* R1926 - AIF3TX1MIX Input 4 Source */
+ { 0x00000787, 0x0080 }, /* R1927 - AIF3TX1MIX Input 4 Volume */
+ { 0x00000788, 0x0000 }, /* R1928 - AIF3TX2MIX Input 1 Source */
+ { 0x00000789, 0x0080 }, /* R1929 - AIF3TX2MIX Input 1 Volume */
+ { 0x0000078A, 0x0000 }, /* R1930 - AIF3TX2MIX Input 2 Source */
+ { 0x0000078B, 0x0080 }, /* R1931 - AIF3TX2MIX Input 2 Volume */
+ { 0x0000078C, 0x0000 }, /* R1932 - AIF3TX2MIX Input 3 Source */
+ { 0x0000078D, 0x0080 }, /* R1933 - AIF3TX2MIX Input 3 Volume */
+ { 0x0000078E, 0x0000 }, /* R1934 - AIF3TX2MIX Input 4 Source */
+ { 0x0000078F, 0x0080 }, /* R1935 - AIF3TX2MIX Input 4 Volume */
+ { 0x000007C0, 0x0000 }, /* R1984 - SLIMTX1MIX Input 1 Source */
+ { 0x000007C1, 0x0080 }, /* R1985 - SLIMTX1MIX Input 1 Volume */
+ { 0x000007C2, 0x0000 }, /* R1986 - SLIMTX1MIX Input 2 Source */
+ { 0x000007C3, 0x0080 }, /* R1987 - SLIMTX1MIX Input 2 Volume */
+ { 0x000007C4, 0x0000 }, /* R1988 - SLIMTX1MIX Input 3 Source */
+ { 0x000007C5, 0x0080 }, /* R1989 - SLIMTX1MIX Input 3 Volume */
+ { 0x000007C6, 0x0000 }, /* R1990 - SLIMTX1MIX Input 4 Source */
+ { 0x000007C7, 0x0080 }, /* R1991 - SLIMTX1MIX Input 4 Volume */
+ { 0x000007C8, 0x0000 }, /* R1992 - SLIMTX2MIX Input 1 Source */
+ { 0x000007C9, 0x0080 }, /* R1993 - SLIMTX2MIX Input 1 Volume */
+ { 0x000007CA, 0x0000 }, /* R1994 - SLIMTX2MIX Input 2 Source */
+ { 0x000007CB, 0x0080 }, /* R1995 - SLIMTX2MIX Input 2 Volume */
+ { 0x000007CC, 0x0000 }, /* R1996 - SLIMTX2MIX Input 3 Source */
+ { 0x000007CD, 0x0080 }, /* R1997 - SLIMTX2MIX Input 3 Volume */
+ { 0x000007CE, 0x0000 }, /* R1998 - SLIMTX2MIX Input 4 Source */
+ { 0x000007CF, 0x0080 }, /* R1999 - SLIMTX2MIX Input 4 Volume */
+ { 0x000007D0, 0x0000 }, /* R2000 - SLIMTX3MIX Input 1 Source */
+ { 0x000007D1, 0x0080 }, /* R2001 - SLIMTX3MIX Input 1 Volume */
+ { 0x000007D2, 0x0000 }, /* R2002 - SLIMTX3MIX Input 2 Source */
+ { 0x000007D3, 0x0080 }, /* R2003 - SLIMTX3MIX Input 2 Volume */
+ { 0x000007D4, 0x0000 }, /* R2004 - SLIMTX3MIX Input 3 Source */
+ { 0x000007D5, 0x0080 }, /* R2005 - SLIMTX3MIX Input 3 Volume */
+ { 0x000007D6, 0x0000 }, /* R2006 - SLIMTX3MIX Input 4 Source */
+ { 0x000007D7, 0x0080 }, /* R2007 - SLIMTX3MIX Input 4 Volume */
+ { 0x000007D8, 0x0000 }, /* R2008 - SLIMTX4MIX Input 1 Source */
+ { 0x000007D9, 0x0080 }, /* R2009 - SLIMTX4MIX Input 1 Volume */
+ { 0x000007DA, 0x0000 }, /* R2010 - SLIMTX4MIX Input 2 Source */
+ { 0x000007DB, 0x0080 }, /* R2011 - SLIMTX4MIX Input 2 Volume */
+ { 0x000007DC, 0x0000 }, /* R2012 - SLIMTX4MIX Input 3 Source */
+ { 0x000007DD, 0x0080 }, /* R2013 - SLIMTX4MIX Input 3 Volume */
+ { 0x000007DE, 0x0000 }, /* R2014 - SLIMTX4MIX Input 4 Source */
+ { 0x000007DF, 0x0080 }, /* R2015 - SLIMTX4MIX Input 4 Volume */
+ { 0x000007E0, 0x0000 }, /* R2016 - SLIMTX5MIX Input 1 Source */
+ { 0x000007E1, 0x0080 }, /* R2017 - SLIMTX5MIX Input 1 Volume */
+ { 0x000007E2, 0x0000 }, /* R2018 - SLIMTX5MIX Input 2 Source */
+ { 0x000007E3, 0x0080 }, /* R2019 - SLIMTX5MIX Input 2 Volume */
+ { 0x000007E4, 0x0000 }, /* R2020 - SLIMTX5MIX Input 3 Source */
+ { 0x000007E5, 0x0080 }, /* R2021 - SLIMTX5MIX Input 3 Volume */
+ { 0x000007E6, 0x0000 }, /* R2022 - SLIMTX5MIX Input 4 Source */
+ { 0x000007E7, 0x0080 }, /* R2023 - SLIMTX5MIX Input 4 Volume */
+ { 0x000007E8, 0x0000 }, /* R2024 - SLIMTX6MIX Input 1 Source */
+ { 0x000007E9, 0x0080 }, /* R2025 - SLIMTX6MIX Input 1 Volume */
+ { 0x000007EA, 0x0000 }, /* R2026 - SLIMTX6MIX Input 2 Source */
+ { 0x000007EB, 0x0080 }, /* R2027 - SLIMTX6MIX Input 2 Volume */
+ { 0x000007EC, 0x0000 }, /* R2028 - SLIMTX6MIX Input 3 Source */
+ { 0x000007ED, 0x0080 }, /* R2029 - SLIMTX6MIX Input 3 Volume */
+ { 0x000007EE, 0x0000 }, /* R2030 - SLIMTX6MIX Input 4 Source */
+ { 0x000007EF, 0x0080 }, /* R2031 - SLIMTX6MIX Input 4 Volume */
+ { 0x000007F0, 0x0000 }, /* R2032 - SLIMTX7MIX Input 1 Source */
+ { 0x000007F1, 0x0080 }, /* R2033 - SLIMTX7MIX Input 1 Volume */
+ { 0x000007F2, 0x0000 }, /* R2034 - SLIMTX7MIX Input 2 Source */
+ { 0x000007F3, 0x0080 }, /* R2035 - SLIMTX7MIX Input 2 Volume */
+ { 0x000007F4, 0x0000 }, /* R2036 - SLIMTX7MIX Input 3 Source */
+ { 0x000007F5, 0x0080 }, /* R2037 - SLIMTX7MIX Input 3 Volume */
+ { 0x000007F6, 0x0000 }, /* R2038 - SLIMTX7MIX Input 4 Source */
+ { 0x000007F7, 0x0080 }, /* R2039 - SLIMTX7MIX Input 4 Volume */
+ { 0x000007F8, 0x0000 }, /* R2040 - SLIMTX8MIX Input 1 Source */
+ { 0x000007F9, 0x0080 }, /* R2041 - SLIMTX8MIX Input 1 Volume */
+ { 0x000007FA, 0x0000 }, /* R2042 - SLIMTX8MIX Input 2 Source */
+ { 0x000007FB, 0x0080 }, /* R2043 - SLIMTX8MIX Input 2 Volume */
+ { 0x000007FC, 0x0000 }, /* R2044 - SLIMTX8MIX Input 3 Source */
+ { 0x000007FD, 0x0080 }, /* R2045 - SLIMTX8MIX Input 3 Volume */
+ { 0x000007FE, 0x0000 }, /* R2046 - SLIMTX8MIX Input 4 Source */
+ { 0x000007FF, 0x0080 }, /* R2047 - SLIMTX8MIX Input 4 Volume */
+ { 0x00000880, 0x0000 }, /* R2176 - EQ1MIX Input 1 Source */
+ { 0x00000881, 0x0080 }, /* R2177 - EQ1MIX Input 1 Volume */
+ { 0x00000882, 0x0000 }, /* R2178 - EQ1MIX Input 2 Source */
+ { 0x00000883, 0x0080 }, /* R2179 - EQ1MIX Input 2 Volume */
+ { 0x00000884, 0x0000 }, /* R2180 - EQ1MIX Input 3 Source */
+ { 0x00000885, 0x0080 }, /* R2181 - EQ1MIX Input 3 Volume */
+ { 0x00000886, 0x0000 }, /* R2182 - EQ1MIX Input 4 Source */
+ { 0x00000887, 0x0080 }, /* R2183 - EQ1MIX Input 4 Volume */
+ { 0x00000888, 0x0000 }, /* R2184 - EQ2MIX Input 1 Source */
+ { 0x00000889, 0x0080 }, /* R2185 - EQ2MIX Input 1 Volume */
+ { 0x0000088A, 0x0000 }, /* R2186 - EQ2MIX Input 2 Source */
+ { 0x0000088B, 0x0080 }, /* R2187 - EQ2MIX Input 2 Volume */
+ { 0x0000088C, 0x0000 }, /* R2188 - EQ2MIX Input 3 Source */
+ { 0x0000088D, 0x0080 }, /* R2189 - EQ2MIX Input 3 Volume */
+ { 0x0000088E, 0x0000 }, /* R2190 - EQ2MIX Input 4 Source */
+ { 0x0000088F, 0x0080 }, /* R2191 - EQ2MIX Input 4 Volume */
+ { 0x00000890, 0x0000 }, /* R2192 - EQ3MIX Input 1 Source */
+ { 0x00000891, 0x0080 }, /* R2193 - EQ3MIX Input 1 Volume */
+ { 0x00000892, 0x0000 }, /* R2194 - EQ3MIX Input 2 Source */
+ { 0x00000893, 0x0080 }, /* R2195 - EQ3MIX Input 2 Volume */
+ { 0x00000894, 0x0000 }, /* R2196 - EQ3MIX Input 3 Source */
+ { 0x00000895, 0x0080 }, /* R2197 - EQ3MIX Input 3 Volume */
+ { 0x00000896, 0x0000 }, /* R2198 - EQ3MIX Input 4 Source */
+ { 0x00000897, 0x0080 }, /* R2199 - EQ3MIX Input 4 Volume */
+ { 0x00000898, 0x0000 }, /* R2200 - EQ4MIX Input 1 Source */
+ { 0x00000899, 0x0080 }, /* R2201 - EQ4MIX Input 1 Volume */
+ { 0x0000089A, 0x0000 }, /* R2202 - EQ4MIX Input 2 Source */
+ { 0x0000089B, 0x0080 }, /* R2203 - EQ4MIX Input 2 Volume */
+ { 0x0000089C, 0x0000 }, /* R2204 - EQ4MIX Input 3 Source */
+ { 0x0000089D, 0x0080 }, /* R2205 - EQ4MIX Input 3 Volume */
+ { 0x0000089E, 0x0000 }, /* R2206 - EQ4MIX Input 4 Source */
+ { 0x0000089F, 0x0080 }, /* R2207 - EQ4MIX Input 4 Volume */
+ { 0x000008C0, 0x0000 }, /* R2240 - DRC1LMIX Input 1 Source */
+ { 0x000008C1, 0x0080 }, /* R2241 - DRC1LMIX Input 1 Volume */
+ { 0x000008C2, 0x0000 }, /* R2242 - DRC1LMIX Input 2 Source */
+ { 0x000008C3, 0x0080 }, /* R2243 - DRC1LMIX Input 2 Volume */
+ { 0x000008C4, 0x0000 }, /* R2244 - DRC1LMIX Input 3 Source */
+ { 0x000008C5, 0x0080 }, /* R2245 - DRC1LMIX Input 3 Volume */
+ { 0x000008C6, 0x0000 }, /* R2246 - DRC1LMIX Input 4 Source */
+ { 0x000008C7, 0x0080 }, /* R2247 - DRC1LMIX Input 4 Volume */
+ { 0x000008C8, 0x0000 }, /* R2248 - DRC1RMIX Input 1 Source */
+ { 0x000008C9, 0x0080 }, /* R2249 - DRC1RMIX Input 1 Volume */
+ { 0x000008CA, 0x0000 }, /* R2250 - DRC1RMIX Input 2 Source */
+ { 0x000008CB, 0x0080 }, /* R2251 - DRC1RMIX Input 2 Volume */
+ { 0x000008CC, 0x0000 }, /* R2252 - DRC1RMIX Input 3 Source */
+ { 0x000008CD, 0x0080 }, /* R2253 - DRC1RMIX Input 3 Volume */
+ { 0x000008CE, 0x0000 }, /* R2254 - DRC1RMIX Input 4 Source */
+ { 0x000008CF, 0x0080 }, /* R2255 - DRC1RMIX Input 4 Volume */
+ { 0x00000900, 0x0000 }, /* R2304 - HPLP1MIX Input 1 Source */
+ { 0x00000901, 0x0080 }, /* R2305 - HPLP1MIX Input 1 Volume */
+ { 0x00000902, 0x0000 }, /* R2306 - HPLP1MIX Input 2 Source */
+ { 0x00000903, 0x0080 }, /* R2307 - HPLP1MIX Input 2 Volume */
+ { 0x00000904, 0x0000 }, /* R2308 - HPLP1MIX Input 3 Source */
+ { 0x00000905, 0x0080 }, /* R2309 - HPLP1MIX Input 3 Volume */
+ { 0x00000906, 0x0000 }, /* R2310 - HPLP1MIX Input 4 Source */
+ { 0x00000907, 0x0080 }, /* R2311 - HPLP1MIX Input 4 Volume */
+ { 0x00000908, 0x0000 }, /* R2312 - HPLP2MIX Input 1 Source */
+ { 0x00000909, 0x0080 }, /* R2313 - HPLP2MIX Input 1 Volume */
+ { 0x0000090A, 0x0000 }, /* R2314 - HPLP2MIX Input 2 Source */
+ { 0x0000090B, 0x0080 }, /* R2315 - HPLP2MIX Input 2 Volume */
+ { 0x0000090C, 0x0000 }, /* R2316 - HPLP2MIX Input 3 Source */
+ { 0x0000090D, 0x0080 }, /* R2317 - HPLP2MIX Input 3 Volume */
+ { 0x0000090E, 0x0000 }, /* R2318 - HPLP2MIX Input 4 Source */
+ { 0x0000090F, 0x0080 }, /* R2319 - HPLP2MIX Input 4 Volume */
+ { 0x00000910, 0x0000 }, /* R2320 - HPLP3MIX Input 1 Source */
+ { 0x00000911, 0x0080 }, /* R2321 - HPLP3MIX Input 1 Volume */
+ { 0x00000912, 0x0000 }, /* R2322 - HPLP3MIX Input 2 Source */
+ { 0x00000913, 0x0080 }, /* R2323 - HPLP3MIX Input 2 Volume */
+ { 0x00000914, 0x0000 }, /* R2324 - HPLP3MIX Input 3 Source */
+ { 0x00000915, 0x0080 }, /* R2325 - HPLP3MIX Input 3 Volume */
+ { 0x00000916, 0x0000 }, /* R2326 - HPLP3MIX Input 4 Source */
+ { 0x00000917, 0x0080 }, /* R2327 - HPLP3MIX Input 4 Volume */
+ { 0x00000918, 0x0000 }, /* R2328 - HPLP4MIX Input 1 Source */
+ { 0x00000919, 0x0080 }, /* R2329 - HPLP4MIX Input 1 Volume */
+ { 0x0000091A, 0x0000 }, /* R2330 - HPLP4MIX Input 2 Source */
+ { 0x0000091B, 0x0080 }, /* R2331 - HPLP4MIX Input 2 Volume */
+ { 0x0000091C, 0x0000 }, /* R2332 - HPLP4MIX Input 3 Source */
+ { 0x0000091D, 0x0080 }, /* R2333 - HPLP4MIX Input 3 Volume */
+ { 0x0000091E, 0x0000 }, /* R2334 - HPLP4MIX Input 4 Source */
+ { 0x0000091F, 0x0080 }, /* R2335 - HPLP4MIX Input 4 Volume */
+ { 0x00000940, 0x0000 }, /* R2368 - DSP1LMIX Input 1 Source */
+ { 0x00000941, 0x0080 }, /* R2369 - DSP1LMIX Input 1 Volume */
+ { 0x00000942, 0x0000 }, /* R2370 - DSP1LMIX Input 2 Source */
+ { 0x00000943, 0x0080 }, /* R2371 - DSP1LMIX Input 2 Volume */
+ { 0x00000944, 0x0000 }, /* R2372 - DSP1LMIX Input 3 Source */
+ { 0x00000945, 0x0080 }, /* R2373 - DSP1LMIX Input 3 Volume */
+ { 0x00000946, 0x0000 }, /* R2374 - DSP1LMIX Input 4 Source */
+ { 0x00000947, 0x0080 }, /* R2375 - DSP1LMIX Input 4 Volume */
+ { 0x00000948, 0x0000 }, /* R2376 - DSP1RMIX Input 1 Source */
+ { 0x00000949, 0x0080 }, /* R2377 - DSP1RMIX Input 1 Volume */
+ { 0x0000094A, 0x0000 }, /* R2378 - DSP1RMIX Input 2 Source */
+ { 0x0000094B, 0x0080 }, /* R2379 - DSP1RMIX Input 2 Volume */
+ { 0x0000094C, 0x0000 }, /* R2380 - DSP1RMIX Input 3 Source */
+ { 0x0000094D, 0x0080 }, /* R2381 - DSP1RMIX Input 3 Volume */
+ { 0x0000094E, 0x0000 }, /* R2382 - DSP1RMIX Input 4 Source */
+ { 0x0000094F, 0x0080 }, /* R2383 - DSP1RMIX Input 4 Volume */
+ { 0x00000950, 0x0000 }, /* R2384 - DSP1AUX1MIX Input 1 Source */
+ { 0x00000958, 0x0000 }, /* R2392 - DSP1AUX2MIX Input 1 Source */
+ { 0x00000960, 0x0000 }, /* R2400 - DSP1AUX3MIX Input 1 Source */
+ { 0x00000968, 0x0000 }, /* R2408 - DSP1AUX4MIX Input 1 Source */
+ { 0x00000970, 0x0000 }, /* R2416 - DSP1AUX5MIX Input 1 Source */
+ { 0x00000978, 0x0000 }, /* R2424 - DSP1AUX6MIX Input 1 Source */
+ { 0x00000A80, 0x0000 }, /* R2688 - ASRC1LMIX Input 1 Source */
+ { 0x00000A88, 0x0000 }, /* R2696 - ASRC1RMIX Input 1 Source */
+ { 0x00000A90, 0x0000 }, /* R2704 - ASRC2LMIX Input 1 Source */
+ { 0x00000A98, 0x0000 }, /* R2712 - ASRC2RMIX Input 1 Source */
+ { 0x00000B00, 0x0000 }, /* R2816 - ISRC1DEC1MIX Input 1 Source */
+ { 0x00000B08, 0x0000 }, /* R2824 - ISRC1DEC2MIX Input 1 Source */
+ { 0x00000B20, 0x0000 }, /* R2848 - ISRC1INT1MIX Input 1 Source */
+ { 0x00000B28, 0x0000 }, /* R2856 - ISRC1INT2MIX Input 1 Source */
+ { 0x00000B40, 0x0000 }, /* R2880 - ISRC2DEC1MIX Input 1 Source */
+ { 0x00000B48, 0x0000 }, /* R2888 - ISRC2DEC2MIX Input 1 Source */
+ { 0x00000B60, 0x0000 }, /* R2912 - ISRC2INT1MIX Input 1 Source */
+ { 0x00000B68, 0x0000 }, /* R2920 - ISRC2INT2MIX Input 1 Source */
+ { 0x00000C00, 0xA101 }, /* R3072 - GPIO1 CTRL */
+ { 0x00000C01, 0xA101 }, /* R3073 - GPIO2 CTRL */
+ { 0x00000C02, 0xA101 }, /* R3074 - GPIO3 CTRL */
+ { 0x00000C03, 0xA101 }, /* R3075 - GPIO4 CTRL */
+ { 0x00000C04, 0xA101 }, /* R3076 - GPIO5 CTRL */
+ { 0x00000C0F, 0x0400 }, /* R3087 - IRQ CTRL 1 */
+ { 0x00000C10, 0x1000 }, /* R3088 - GPIO Debounce Config */
+ { 0x00000C20, 0x8002 }, /* R3104 - Misc Pad Ctrl 1 */
{ 0x00000C21, 0x0001 }, /* R3105 - Misc Pad Ctrl 2 */
- { 0x00000C22, 0x0000 }, /* R3106 - Misc Pad Ctrl 3 */
- { 0x00000C23, 0x0000 }, /* R3107 - Misc Pad Ctrl 4 */
- { 0x00000C24, 0x0000 }, /* R3108 - Misc Pad Ctrl 5 */
- { 0x00000C25, 0x0000 }, /* R3109 - Misc Pad Ctrl 6 */
- { 0x00000D08, 0xFFFF }, /* R3336 - Interrupt Status 1 Mask */
- { 0x00000D09, 0xFFFF }, /* R3337 - Interrupt Status 2 Mask */
- { 0x00000D0A, 0xFFFF }, /* R3338 - Interrupt Status 3 Mask */
- { 0x00000D0B, 0xFFFF }, /* R3339 - Interrupt Status 4 Mask */
- { 0x00000D0C, 0xFEFF }, /* R3340 - Interrupt Status 5 Mask */
- { 0x00000D0F, 0x0000 }, /* R3343 - Interrupt Control */
- { 0x00000D18, 0xFFFF }, /* R3352 - IRQ2 Status 1 Mask */
- { 0x00000D19, 0xFFFF }, /* R3353 - IRQ2 Status 2 Mask */
- { 0x00000D1A, 0xFFFF }, /* R3354 - IRQ2 Status 3 Mask */
- { 0x00000D1B, 0xFFFF }, /* R3355 - IRQ2 Status 4 Mask */
- { 0x00000D1C, 0xFFFF }, /* R3356 - IRQ2 Status 5 Mask */
- { 0x00000D1F, 0x0000 }, /* R3359 - IRQ2 Control */
+ { 0x00000C22, 0x0000 }, /* R3106 - Misc Pad Ctrl 3 */
+ { 0x00000C23, 0x0000 }, /* R3107 - Misc Pad Ctrl 4 */
+ { 0x00000C24, 0x0000 }, /* R3108 - Misc Pad Ctrl 5 */
+ { 0x00000C25, 0x0000 }, /* R3109 - Misc Pad Ctrl 6 */
+ { 0x00000D08, 0xFFFF }, /* R3336 - Interrupt Status 1 Mask */
+ { 0x00000D09, 0xFFFF }, /* R3337 - Interrupt Status 2 Mask */
+ { 0x00000D0A, 0xFFFF }, /* R3338 - Interrupt Status 3 Mask */
+ { 0x00000D0B, 0xFFFF }, /* R3339 - Interrupt Status 4 Mask */
+ { 0x00000D0C, 0xFEFF }, /* R3340 - Interrupt Status 5 Mask */
+ { 0x00000D0F, 0x0000 }, /* R3343 - Interrupt Control */
+ { 0x00000D18, 0xFFFF }, /* R3352 - IRQ2 Status 1 Mask */
+ { 0x00000D19, 0xFFFF }, /* R3353 - IRQ2 Status 2 Mask */
+ { 0x00000D1A, 0xFFFF }, /* R3354 - IRQ2 Status 3 Mask */
+ { 0x00000D1B, 0xFFFF }, /* R3355 - IRQ2 Status 4 Mask */
+ { 0x00000D1C, 0xFFFF }, /* R3356 - IRQ2 Status 5 Mask */
+ { 0x00000D1F, 0x0000 }, /* R3359 - IRQ2 Control */
{ 0x00000D41, 0x0000 }, /* R3393 - ADSP2 IRQ0 */
- { 0x00000D53, 0xFFFF }, /* R3411 - AOD IRQ Mask IRQ1 */
- { 0x00000D54, 0xFFFF }, /* R3412 - AOD IRQ Mask IRQ2 */
- { 0x00000D56, 0x0000 }, /* R3414 - Jack detect debounce */
- { 0x00000E00, 0x0000 }, /* R3584 - FX_Ctrl1 */
- { 0x00000E10, 0x6318 }, /* R3600 - EQ1_1 */
- { 0x00000E11, 0x6300 }, /* R3601 - EQ1_2 */
- { 0x00000E12, 0x0FC8 }, /* R3602 - EQ1_3 */
- { 0x00000E13, 0x03FE }, /* R3603 - EQ1_4 */
- { 0x00000E14, 0x00E0 }, /* R3604 - EQ1_5 */
- { 0x00000E15, 0x1EC4 }, /* R3605 - EQ1_6 */
- { 0x00000E16, 0xF136 }, /* R3606 - EQ1_7 */
- { 0x00000E17, 0x0409 }, /* R3607 - EQ1_8 */
- { 0x00000E18, 0x04CC }, /* R3608 - EQ1_9 */
- { 0x00000E19, 0x1C9B }, /* R3609 - EQ1_10 */
- { 0x00000E1A, 0xF337 }, /* R3610 - EQ1_11 */
- { 0x00000E1B, 0x040B }, /* R3611 - EQ1_12 */
- { 0x00000E1C, 0x0CBB }, /* R3612 - EQ1_13 */
- { 0x00000E1D, 0x16F8 }, /* R3613 - EQ1_14 */
- { 0x00000E1E, 0xF7D9 }, /* R3614 - EQ1_15 */
- { 0x00000E1F, 0x040A }, /* R3615 - EQ1_16 */
- { 0x00000E20, 0x1F14 }, /* R3616 - EQ1_17 */
- { 0x00000E21, 0x058C }, /* R3617 - EQ1_18 */
- { 0x00000E22, 0x0563 }, /* R3618 - EQ1_19 */
- { 0x00000E23, 0x4000 }, /* R3619 - EQ1_20 */
- { 0x00000E24, 0x0B75 }, /* R3620 - EQ1_21 */
- { 0x00000E26, 0x6318 }, /* R3622 - EQ2_1 */
- { 0x00000E27, 0x6300 }, /* R3623 - EQ2_2 */
- { 0x00000E28, 0x0FC8 }, /* R3624 - EQ2_3 */
- { 0x00000E29, 0x03FE }, /* R3625 - EQ2_4 */
- { 0x00000E2A, 0x00E0 }, /* R3626 - EQ2_5 */
- { 0x00000E2B, 0x1EC4 }, /* R3627 - EQ2_6 */
- { 0x00000E2C, 0xF136 }, /* R3628 - EQ2_7 */
- { 0x00000E2D, 0x0409 }, /* R3629 - EQ2_8 */
- { 0x00000E2E, 0x04CC }, /* R3630 - EQ2_9 */
- { 0x00000E2F, 0x1C9B }, /* R3631 - EQ2_10 */
- { 0x00000E30, 0xF337 }, /* R3632 - EQ2_11 */
- { 0x00000E31, 0x040B }, /* R3633 - EQ2_12 */
- { 0x00000E32, 0x0CBB }, /* R3634 - EQ2_13 */
- { 0x00000E33, 0x16F8 }, /* R3635 - EQ2_14 */
- { 0x00000E34, 0xF7D9 }, /* R3636 - EQ2_15 */
- { 0x00000E35, 0x040A }, /* R3637 - EQ2_16 */
- { 0x00000E36, 0x1F14 }, /* R3638 - EQ2_17 */
- { 0x00000E37, 0x058C }, /* R3639 - EQ2_18 */
- { 0x00000E38, 0x0563 }, /* R3640 - EQ2_19 */
- { 0x00000E39, 0x4000 }, /* R3641 - EQ2_20 */
- { 0x00000E3A, 0x0B75 }, /* R3642 - EQ2_21 */
- { 0x00000E3C, 0x6318 }, /* R3644 - EQ3_1 */
- { 0x00000E3D, 0x6300 }, /* R3645 - EQ3_2 */
- { 0x00000E3E, 0x0FC8 }, /* R3646 - EQ3_3 */
- { 0x00000E3F, 0x03FE }, /* R3647 - EQ3_4 */
- { 0x00000E40, 0x00E0 }, /* R3648 - EQ3_5 */
- { 0x00000E41, 0x1EC4 }, /* R3649 - EQ3_6 */
- { 0x00000E42, 0xF136 }, /* R3650 - EQ3_7 */
- { 0x00000E43, 0x0409 }, /* R3651 - EQ3_8 */
- { 0x00000E44, 0x04CC }, /* R3652 - EQ3_9 */
- { 0x00000E45, 0x1C9B }, /* R3653 - EQ3_10 */
- { 0x00000E46, 0xF337 }, /* R3654 - EQ3_11 */
- { 0x00000E47, 0x040B }, /* R3655 - EQ3_12 */
- { 0x00000E48, 0x0CBB }, /* R3656 - EQ3_13 */
- { 0x00000E49, 0x16F8 }, /* R3657 - EQ3_14 */
- { 0x00000E4A, 0xF7D9 }, /* R3658 - EQ3_15 */
- { 0x00000E4B, 0x040A }, /* R3659 - EQ3_16 */
- { 0x00000E4C, 0x1F14 }, /* R3660 - EQ3_17 */
- { 0x00000E4D, 0x058C }, /* R3661 - EQ3_18 */
- { 0x00000E4E, 0x0563 }, /* R3662 - EQ3_19 */
- { 0x00000E4F, 0x4000 }, /* R3663 - EQ3_20 */
- { 0x00000E50, 0x0B75 }, /* R3664 - EQ3_21 */
- { 0x00000E52, 0x6318 }, /* R3666 - EQ4_1 */
- { 0x00000E53, 0x6300 }, /* R3667 - EQ4_2 */
- { 0x00000E54, 0x0FC8 }, /* R3668 - EQ4_3 */
- { 0x00000E55, 0x03FE }, /* R3669 - EQ4_4 */
- { 0x00000E56, 0x00E0 }, /* R3670 - EQ4_5 */
- { 0x00000E57, 0x1EC4 }, /* R3671 - EQ4_6 */
- { 0x00000E58, 0xF136 }, /* R3672 - EQ4_7 */
- { 0x00000E59, 0x0409 }, /* R3673 - EQ4_8 */
- { 0x00000E5A, 0x04CC }, /* R3674 - EQ4_9 */
- { 0x00000E5B, 0x1C9B }, /* R3675 - EQ4_10 */
- { 0x00000E5C, 0xF337 }, /* R3676 - EQ4_11 */
- { 0x00000E5D, 0x040B }, /* R3677 - EQ4_12 */
- { 0x00000E5E, 0x0CBB }, /* R3678 - EQ4_13 */
- { 0x00000E5F, 0x16F8 }, /* R3679 - EQ4_14 */
- { 0x00000E60, 0xF7D9 }, /* R3680 - EQ4_15 */
- { 0x00000E61, 0x040A }, /* R3681 - EQ4_16 */
- { 0x00000E62, 0x1F14 }, /* R3682 - EQ4_17 */
- { 0x00000E63, 0x058C }, /* R3683 - EQ4_18 */
- { 0x00000E64, 0x0563 }, /* R3684 - EQ4_19 */
- { 0x00000E65, 0x4000 }, /* R3685 - EQ4_20 */
- { 0x00000E66, 0x0B75 }, /* R3686 - EQ4_21 */
- { 0x00000E80, 0x0018 }, /* R3712 - DRC1 ctrl1 */
- { 0x00000E81, 0x0933 }, /* R3713 - DRC1 ctrl2 */
- { 0x00000E82, 0x0018 }, /* R3714 - DRC1 ctrl3 */
- { 0x00000E83, 0x0000 }, /* R3715 - DRC1 ctrl4 */
- { 0x00000E84, 0x0000 }, /* R3716 - DRC1 ctrl5 */
- { 0x00000EC0, 0x0000 }, /* R3776 - HPLPF1_1 */
- { 0x00000EC1, 0x0000 }, /* R3777 - HPLPF1_2 */
- { 0x00000EC4, 0x0000 }, /* R3780 - HPLPF2_1 */
- { 0x00000EC5, 0x0000 }, /* R3781 - HPLPF2_2 */
- { 0x00000EC8, 0x0000 }, /* R3784 - HPLPF3_1 */
- { 0x00000EC9, 0x0000 }, /* R3785 - HPLPF3_2 */
- { 0x00000ECC, 0x0000 }, /* R3788 - HPLPF4_1 */
- { 0x00000ECD, 0x0000 }, /* R3789 - HPLPF4_2 */
- { 0x00000EE0, 0x0000 }, /* R3808 - ASRC_ENABLE */
- { 0x00000EE2, 0x0000 }, /* R3810 - ASRC_RATE1 */
+ { 0x00000D53, 0xFFFF }, /* R3411 - AOD IRQ Mask IRQ1 */
+ { 0x00000D54, 0xFFFF }, /* R3412 - AOD IRQ Mask IRQ2 */
+ { 0x00000D56, 0x0000 }, /* R3414 - Jack detect debounce */
+ { 0x00000E00, 0x0000 }, /* R3584 - FX_Ctrl1 */
+ { 0x00000E10, 0x6318 }, /* R3600 - EQ1_1 */
+ { 0x00000E11, 0x6300 }, /* R3601 - EQ1_2 */
+ { 0x00000E12, 0x0FC8 }, /* R3602 - EQ1_3 */
+ { 0x00000E13, 0x03FE }, /* R3603 - EQ1_4 */
+ { 0x00000E14, 0x00E0 }, /* R3604 - EQ1_5 */
+ { 0x00000E15, 0x1EC4 }, /* R3605 - EQ1_6 */
+ { 0x00000E16, 0xF136 }, /* R3606 - EQ1_7 */
+ { 0x00000E17, 0x0409 }, /* R3607 - EQ1_8 */
+ { 0x00000E18, 0x04CC }, /* R3608 - EQ1_9 */
+ { 0x00000E19, 0x1C9B }, /* R3609 - EQ1_10 */
+ { 0x00000E1A, 0xF337 }, /* R3610 - EQ1_11 */
+ { 0x00000E1B, 0x040B }, /* R3611 - EQ1_12 */
+ { 0x00000E1C, 0x0CBB }, /* R3612 - EQ1_13 */
+ { 0x00000E1D, 0x16F8 }, /* R3613 - EQ1_14 */
+ { 0x00000E1E, 0xF7D9 }, /* R3614 - EQ1_15 */
+ { 0x00000E1F, 0x040A }, /* R3615 - EQ1_16 */
+ { 0x00000E20, 0x1F14 }, /* R3616 - EQ1_17 */
+ { 0x00000E21, 0x058C }, /* R3617 - EQ1_18 */
+ { 0x00000E22, 0x0563 }, /* R3618 - EQ1_19 */
+ { 0x00000E23, 0x4000 }, /* R3619 - EQ1_20 */
+ { 0x00000E24, 0x0B75 }, /* R3620 - EQ1_21 */
+ { 0x00000E26, 0x6318 }, /* R3622 - EQ2_1 */
+ { 0x00000E27, 0x6300 }, /* R3623 - EQ2_2 */
+ { 0x00000E28, 0x0FC8 }, /* R3624 - EQ2_3 */
+ { 0x00000E29, 0x03FE }, /* R3625 - EQ2_4 */
+ { 0x00000E2A, 0x00E0 }, /* R3626 - EQ2_5 */
+ { 0x00000E2B, 0x1EC4 }, /* R3627 - EQ2_6 */
+ { 0x00000E2C, 0xF136 }, /* R3628 - EQ2_7 */
+ { 0x00000E2D, 0x0409 }, /* R3629 - EQ2_8 */
+ { 0x00000E2E, 0x04CC }, /* R3630 - EQ2_9 */
+ { 0x00000E2F, 0x1C9B }, /* R3631 - EQ2_10 */
+ { 0x00000E30, 0xF337 }, /* R3632 - EQ2_11 */
+ { 0x00000E31, 0x040B }, /* R3633 - EQ2_12 */
+ { 0x00000E32, 0x0CBB }, /* R3634 - EQ2_13 */
+ { 0x00000E33, 0x16F8 }, /* R3635 - EQ2_14 */
+ { 0x00000E34, 0xF7D9 }, /* R3636 - EQ2_15 */
+ { 0x00000E35, 0x040A }, /* R3637 - EQ2_16 */
+ { 0x00000E36, 0x1F14 }, /* R3638 - EQ2_17 */
+ { 0x00000E37, 0x058C }, /* R3639 - EQ2_18 */
+ { 0x00000E38, 0x0563 }, /* R3640 - EQ2_19 */
+ { 0x00000E39, 0x4000 }, /* R3641 - EQ2_20 */
+ { 0x00000E3A, 0x0B75 }, /* R3642 - EQ2_21 */
+ { 0x00000E3C, 0x6318 }, /* R3644 - EQ3_1 */
+ { 0x00000E3D, 0x6300 }, /* R3645 - EQ3_2 */
+ { 0x00000E3E, 0x0FC8 }, /* R3646 - EQ3_3 */
+ { 0x00000E3F, 0x03FE }, /* R3647 - EQ3_4 */
+ { 0x00000E40, 0x00E0 }, /* R3648 - EQ3_5 */
+ { 0x00000E41, 0x1EC4 }, /* R3649 - EQ3_6 */
+ { 0x00000E42, 0xF136 }, /* R3650 - EQ3_7 */
+ { 0x00000E43, 0x0409 }, /* R3651 - EQ3_8 */
+ { 0x00000E44, 0x04CC }, /* R3652 - EQ3_9 */
+ { 0x00000E45, 0x1C9B }, /* R3653 - EQ3_10 */
+ { 0x00000E46, 0xF337 }, /* R3654 - EQ3_11 */
+ { 0x00000E47, 0x040B }, /* R3655 - EQ3_12 */
+ { 0x00000E48, 0x0CBB }, /* R3656 - EQ3_13 */
+ { 0x00000E49, 0x16F8 }, /* R3657 - EQ3_14 */
+ { 0x00000E4A, 0xF7D9 }, /* R3658 - EQ3_15 */
+ { 0x00000E4B, 0x040A }, /* R3659 - EQ3_16 */
+ { 0x00000E4C, 0x1F14 }, /* R3660 - EQ3_17 */
+ { 0x00000E4D, 0x058C }, /* R3661 - EQ3_18 */
+ { 0x00000E4E, 0x0563 }, /* R3662 - EQ3_19 */
+ { 0x00000E4F, 0x4000 }, /* R3663 - EQ3_20 */
+ { 0x00000E50, 0x0B75 }, /* R3664 - EQ3_21 */
+ { 0x00000E52, 0x6318 }, /* R3666 - EQ4_1 */
+ { 0x00000E53, 0x6300 }, /* R3667 - EQ4_2 */
+ { 0x00000E54, 0x0FC8 }, /* R3668 - EQ4_3 */
+ { 0x00000E55, 0x03FE }, /* R3669 - EQ4_4 */
+ { 0x00000E56, 0x00E0 }, /* R3670 - EQ4_5 */
+ { 0x00000E57, 0x1EC4 }, /* R3671 - EQ4_6 */
+ { 0x00000E58, 0xF136 }, /* R3672 - EQ4_7 */
+ { 0x00000E59, 0x0409 }, /* R3673 - EQ4_8 */
+ { 0x00000E5A, 0x04CC }, /* R3674 - EQ4_9 */
+ { 0x00000E5B, 0x1C9B }, /* R3675 - EQ4_10 */
+ { 0x00000E5C, 0xF337 }, /* R3676 - EQ4_11 */
+ { 0x00000E5D, 0x040B }, /* R3677 - EQ4_12 */
+ { 0x00000E5E, 0x0CBB }, /* R3678 - EQ4_13 */
+ { 0x00000E5F, 0x16F8 }, /* R3679 - EQ4_14 */
+ { 0x00000E60, 0xF7D9 }, /* R3680 - EQ4_15 */
+ { 0x00000E61, 0x040A }, /* R3681 - EQ4_16 */
+ { 0x00000E62, 0x1F14 }, /* R3682 - EQ4_17 */
+ { 0x00000E63, 0x058C }, /* R3683 - EQ4_18 */
+ { 0x00000E64, 0x0563 }, /* R3684 - EQ4_19 */
+ { 0x00000E65, 0x4000 }, /* R3685 - EQ4_20 */
+ { 0x00000E66, 0x0B75 }, /* R3686 - EQ4_21 */
+ { 0x00000E80, 0x0018 }, /* R3712 - DRC1 ctrl1 */
+ { 0x00000E81, 0x0933 }, /* R3713 - DRC1 ctrl2 */
+ { 0x00000E82, 0x0018 }, /* R3714 - DRC1 ctrl3 */
+ { 0x00000E83, 0x0000 }, /* R3715 - DRC1 ctrl4 */
+ { 0x00000E84, 0x0000 }, /* R3716 - DRC1 ctrl5 */
+ { 0x00000EC0, 0x0000 }, /* R3776 - HPLPF1_1 */
+ { 0x00000EC1, 0x0000 }, /* R3777 - HPLPF1_2 */
+ { 0x00000EC4, 0x0000 }, /* R3780 - HPLPF2_1 */
+ { 0x00000EC5, 0x0000 }, /* R3781 - HPLPF2_2 */
+ { 0x00000EC8, 0x0000 }, /* R3784 - HPLPF3_1 */
+ { 0x00000EC9, 0x0000 }, /* R3785 - HPLPF3_2 */
+ { 0x00000ECC, 0x0000 }, /* R3788 - HPLPF4_1 */
+ { 0x00000ECD, 0x0000 }, /* R3789 - HPLPF4_2 */
+ { 0x00000EE0, 0x0000 }, /* R3808 - ASRC_ENABLE */
+ { 0x00000EE2, 0x0000 }, /* R3810 - ASRC_RATE1 */
{ 0x00000EE3, 0x4000 }, /* R3811 - ASRC_RATE2 */
- { 0x00000EF0, 0x0000 }, /* R3824 - ISRC 1 CTRL 1 */
- { 0x00000EF1, 0x0000 }, /* R3825 - ISRC 1 CTRL 2 */
- { 0x00000EF2, 0x0000 }, /* R3826 - ISRC 1 CTRL 3 */
- { 0x00000EF3, 0x0000 }, /* R3827 - ISRC 2 CTRL 1 */
- { 0x00000EF4, 0x0000 }, /* R3828 - ISRC 2 CTRL 2 */
- { 0x00000EF5, 0x0000 }, /* R3829 - ISRC 2 CTRL 3 */
- { 0x00001100, 0x0010 }, /* R4352 - DSP1 Control 1 */
+ { 0x00000EF0, 0x0000 }, /* R3824 - ISRC 1 CTRL 1 */
+ { 0x00000EF1, 0x0000 }, /* R3825 - ISRC 1 CTRL 2 */
+ { 0x00000EF2, 0x0000 }, /* R3826 - ISRC 1 CTRL 3 */
+ { 0x00000EF3, 0x0000 }, /* R3827 - ISRC 2 CTRL 1 */
+ { 0x00000EF4, 0x0000 }, /* R3828 - ISRC 2 CTRL 2 */
+ { 0x00000EF5, 0x0000 }, /* R3829 - ISRC 2 CTRL 3 */
+ { 0x00001100, 0x0010 }, /* R4352 - DSP1 Control 1 */
};
static bool wm5102_readable_register(struct device *dev, unsigned int reg)
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index 8588dbad3301..953d0790ffd5 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -406,8 +406,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
goto err;
}
- ret = regulator_bulk_enable(wm8994->num_supplies,
- wm8994->supplies);
+ ret = regulator_bulk_enable(wm8994->num_supplies, wm8994->supplies);
if (ret != 0) {
dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret);
goto err_regulator_free;
@@ -612,8 +611,7 @@ static void wm8994_device_exit(struct wm8994 *wm8994)
{
pm_runtime_disable(wm8994->dev);
wm8994_irq_exit(wm8994);
- regulator_bulk_disable(wm8994->num_supplies,
- wm8994->supplies);
+ regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies);
regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
mfd_remove_devices(wm8994->dev);
}
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 543eadd230e5..1076b9d89df3 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -496,8 +496,7 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
* Returns enum mmc_blk_status after checking errors.
*/
static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host,
- struct mmc_request *mrq,
- struct mmc_async_req *next_req)
+ struct mmc_request *mrq)
{
struct mmc_command *cmd;
struct mmc_context_info *context_info = &host->context_info;
@@ -507,7 +506,7 @@ static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host,
wait_event_interruptible(context_info->wait,
(context_info->is_done_rcv ||
context_info->is_new_req));
- context_info->is_waiting_last_req = false;
+
if (context_info->is_done_rcv) {
context_info->is_done_rcv = false;
cmd = mrq->cmd;
@@ -527,10 +526,9 @@ static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host,
__mmc_start_request(host, mrq);
continue; /* wait for done/new event again */
}
- } else if (context_info->is_new_req) {
- if (!next_req)
- return MMC_BLK_NEW_REQUEST;
}
+
+ return MMC_BLK_NEW_REQUEST;
}
mmc_retune_release(host);
return status;
@@ -660,7 +658,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
mmc_pre_req(host, areq->mrq);
if (host->areq) {
- status = mmc_wait_for_data_req_done(host, host->areq->mrq, areq);
+ status = mmc_wait_for_data_req_done(host, host->areq->mrq);
if (status == MMC_BLK_NEW_REQUEST) {
if (ret_stat)
*ret_stat = status;
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index deb90c2ff6b4..a614f37faf27 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -223,6 +223,7 @@ static int mmc_decode_scr(struct mmc_card *card)
static int mmc_read_ssr(struct mmc_card *card)
{
unsigned int au, es, et, eo;
+ u32 *raw_ssr;
int i;
if (!(card->csd.cmdclass & CCC_APP_SPEC)) {
@@ -231,14 +232,21 @@ static int mmc_read_ssr(struct mmc_card *card)
return 0;
}
- if (mmc_app_sd_status(card, card->raw_ssr)) {
+ raw_ssr = kmalloc(sizeof(card->raw_ssr), GFP_KERNEL);
+ if (!raw_ssr)
+ return -ENOMEM;
+
+ if (mmc_app_sd_status(card, raw_ssr)) {
pr_warn("%s: problem reading SD Status register\n",
mmc_hostname(card->host));
+ kfree(raw_ssr);
return 0;
}
for (i = 0; i < 16; i++)
- card->raw_ssr[i] = be32_to_cpu(card->raw_ssr[i]);
+ card->raw_ssr[i] = be32_to_cpu(raw_ssr[i]);
+
+ kfree(raw_ssr);
/*
* UNSTUFF_BITS only works with four u32s so we have to offset the
diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c
index 1501cfdac473..4b0ecb981842 100644
--- a/drivers/mmc/host/sdhci-cadence.c
+++ b/drivers/mmc/host/sdhci-cadence.c
@@ -262,6 +262,7 @@ disable_clk:
}
static const struct of_device_id sdhci_cdns_match[] = {
+ { .compatible = "socionext,uniphier-sd4hc" },
{ .compatible = "cdns,sd4hc" },
{ /* sentinel */ }
};
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 111991e5b9a0..23909804ffb8 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1576,6 +1576,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
unsigned long flags;
u8 ctrl;
+ if (ios->power_mode == MMC_POWER_UNDEFINED)
+ return;
+
spin_lock_irqsave(&host->lock, flags);
if (host->flags & SDHCI_DEVICE_DEAD) {
@@ -2938,22 +2941,24 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
sdhci_init(host, 0);
- /* Force clock and power re-program */
- host->pwr = 0;
- host->clock = 0;
- mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios);
- mmc->ops->set_ios(mmc, &mmc->ios);
+ if (mmc->ios.power_mode != MMC_POWER_UNDEFINED) {
+ /* Force clock and power re-program */
+ host->pwr = 0;
+ host->clock = 0;
+ mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios);
+ mmc->ops->set_ios(mmc, &mmc->ios);
- if ((host_flags & SDHCI_PV_ENABLED) &&
- !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
- spin_lock_irqsave(&host->lock, flags);
- sdhci_enable_preset_value(host, true);
- spin_unlock_irqrestore(&host->lock, flags);
- }
+ if ((host_flags & SDHCI_PV_ENABLED) &&
+ !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
+ spin_lock_irqsave(&host->lock, flags);
+ sdhci_enable_preset_value(host, true);
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
- if ((mmc->caps2 & MMC_CAP2_HS400_ES) &&
- mmc->ops->hs400_enhanced_strobe)
- mmc->ops->hs400_enhanced_strobe(mmc, &mmc->ios);
+ if ((mmc->caps2 & MMC_CAP2_HS400_ES) &&
+ mmc->ops->hs400_enhanced_strobe)
+ mmc->ops->hs400_enhanced_strobe(mmc, &mmc->ios);
+ }
spin_lock_irqsave(&host->lock, flags);
diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c
index 377947580203..283ff7e17a0f 100644
--- a/drivers/mtd/bcm47xxpart.c
+++ b/drivers/mtd/bcm47xxpart.c
@@ -229,12 +229,10 @@ static int bcm47xxpart_parse(struct mtd_info *master,
last_trx_part = curr_part - 1;
- /*
- * We have whole TRX scanned, skip to the next part. Use
- * roundown (not roundup), as the loop will increase
- * offset in next step.
- */
- offset = rounddown(offset + trx->length, blocksize);
+ /* Jump to the end of TRX */
+ offset = roundup(offset + trx->length, blocksize);
+ /* Next loop iteration will increase the offset */
+ offset -= blocksize;
continue;
}
diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c
index 1c65c15b31a1..514be04c0b6c 100644
--- a/drivers/mtd/devices/bcm47xxsflash.c
+++ b/drivers/mtd/devices/bcm47xxsflash.c
@@ -296,16 +296,30 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
dev_err(dev, "can't request region for resource %pR\n", res);
return -EBUSY;
}
- b47s->window = ioremap_cache(res->start, resource_size(res));
- if (!b47s->window) {
- dev_err(dev, "ioremap failed for resource %pR\n", res);
- return -ENOMEM;
- }
b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
b47s->cc_read = bcm47xxsflash_bcma_cc_read;
b47s->cc_write = bcm47xxsflash_bcma_cc_write;
+ /*
+ * On old MIPS devices cache was magically invalidated when needed,
+ * allowing us to use cached access and gain some performance. Trying
+ * the same on ARM based BCM53573 results in flash corruptions, we need
+ * to use uncached access for it.
+ *
+ * It may be arch specific, but right now there is only 1 ARM SoC using
+ * this driver, so let's follow Broadcom's reference code and check
+ * ChipCommon revision.
+ */
+ if (b47s->bcma_cc->core->id.rev == 54)
+ b47s->window = ioremap_nocache(res->start, resource_size(res));
+ else
+ b47s->window = ioremap_cache(res->start, resource_size(res));
+ if (!b47s->window) {
+ dev_err(dev, "ioremap failed for resource %pR\n", res);
+ return -ENOMEM;
+ }
+
switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) {
case BCMA_CC_FLASHT_STSER:
b47s->type = BCM47XXSFLASH_TYPE_ST;
diff --git a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c
index 093edd51bdc7..9b1c13aa9f20 100644
--- a/drivers/mtd/maps/sc520cdp.c
+++ b/drivers/mtd/maps/sc520cdp.c
@@ -227,7 +227,7 @@ static void sc520cdp_setup_par(void)
static int __init init_sc520cdp(void)
{
- int i, devices_found = 0;
+ int i, j, devices_found = 0;
#ifdef REPROGRAM_PAR
/* reprogram PAR registers so flash appears at the desired addresses */
@@ -243,6 +243,12 @@ static int __init init_sc520cdp(void)
if (!sc520cdp_map[i].virt) {
printk("Failed to ioremap_nocache\n");
+ for (j = 0; j < i; j++) {
+ if (mymtd[j]) {
+ map_destroy(mymtd[j]);
+ iounmap(sc520cdp_map[j].virt);
+ }
+ }
return -EIO;
}
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index d46e4adf6d2b..052772f7caef 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -46,8 +46,7 @@
#include "mtdcore.h"
-static struct backing_dev_info mtd_bdi = {
-};
+static struct backing_dev_info *mtd_bdi;
#ifdef CONFIG_PM_SLEEP
@@ -500,7 +499,7 @@ int add_mtd_device(struct mtd_info *mtd)
if (WARN_ONCE(mtd->backing_dev_info, "MTD already registered\n"))
return -EEXIST;
- mtd->backing_dev_info = &mtd_bdi;
+ mtd->backing_dev_info = mtd_bdi;
BUG_ON(mtd->writesize == 0);
mutex_lock(&mtd_table_mutex);
@@ -1274,8 +1273,8 @@ static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf,
int section,
struct mtd_oob_region *oobregion))
{
- struct mtd_oob_region oobregion = { };
- int section = 0, ret;
+ struct mtd_oob_region oobregion;
+ int section, ret;
ret = mtd_ooblayout_find_region(mtd, start, &section,
&oobregion, iter);
@@ -1283,7 +1282,7 @@ static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf,
while (!ret) {
int cnt;
- cnt = oobregion.length > nbytes ? nbytes : oobregion.length;
+ cnt = min_t(int, nbytes, oobregion.length);
memcpy(buf, oobbuf + oobregion.offset, cnt);
buf += cnt;
nbytes -= cnt;
@@ -1317,8 +1316,8 @@ static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf,
int section,
struct mtd_oob_region *oobregion))
{
- struct mtd_oob_region oobregion = { };
- int section = 0, ret;
+ struct mtd_oob_region oobregion;
+ int section, ret;
ret = mtd_ooblayout_find_region(mtd, start, &section,
&oobregion, iter);
@@ -1326,7 +1325,7 @@ static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf,
while (!ret) {
int cnt;
- cnt = oobregion.length > nbytes ? nbytes : oobregion.length;
+ cnt = min_t(int, nbytes, oobregion.length);
memcpy(oobbuf + oobregion.offset, buf, cnt);
buf += cnt;
nbytes -= cnt;
@@ -1354,7 +1353,7 @@ static int mtd_ooblayout_count_bytes(struct mtd_info *mtd,
int section,
struct mtd_oob_region *oobregion))
{
- struct mtd_oob_region oobregion = { };
+ struct mtd_oob_region oobregion;
int section = 0, ret, nbytes = 0;
while (1) {
@@ -1771,18 +1770,20 @@ static const struct file_operations mtd_proc_ops = {
/*====================================================================*/
/* Init code */
-static int __init mtd_bdi_init(struct backing_dev_info *bdi, const char *name)
+static struct backing_dev_info * __init mtd_bdi_init(char *name)
{
+ struct backing_dev_info *bdi;
int ret;
- ret = bdi_init(bdi);
- if (!ret)
- ret = bdi_register(bdi, NULL, "%s", name);
+ bdi = kzalloc(sizeof(*bdi), GFP_KERNEL);
+ if (!bdi)
+ return ERR_PTR(-ENOMEM);
+ ret = bdi_setup_and_register(bdi, name);
if (ret)
- bdi_destroy(bdi);
+ kfree(bdi);
- return ret;
+ return ret ? ERR_PTR(ret) : bdi;
}
static struct proc_dir_entry *proc_mtd;
@@ -1795,9 +1796,11 @@ static int __init init_mtd(void)
if (ret)
goto err_reg;
- ret = mtd_bdi_init(&mtd_bdi, "mtd");
- if (ret)
+ mtd_bdi = mtd_bdi_init("mtd");
+ if (IS_ERR(mtd_bdi)) {
+ ret = PTR_ERR(mtd_bdi);
goto err_bdi;
+ }
proc_mtd = proc_create("mtd", 0, NULL, &mtd_proc_ops);
@@ -1810,6 +1813,8 @@ static int __init init_mtd(void)
out_procfs:
if (proc_mtd)
remove_proc_entry("mtd", NULL);
+ bdi_destroy(mtd_bdi);
+ kfree(mtd_bdi);
err_bdi:
class_unregister(&mtd_class);
err_reg:
@@ -1823,7 +1828,8 @@ static void __exit cleanup_mtd(void)
if (proc_mtd)
remove_proc_entry("mtd", NULL);
class_unregister(&mtd_class);
- bdi_destroy(&mtd_bdi);
+ bdi_destroy(mtd_bdi);
+ kfree(mtd_bdi);
idr_destroy(&mtd_idr);
}
diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c
index cb06bdd21a1b..c40e2c951758 100644
--- a/drivers/mtd/mtdswap.c
+++ b/drivers/mtd/mtdswap.c
@@ -587,7 +587,7 @@ retry:
ret = wait_event_interruptible(wq, erase.state == MTD_ERASE_DONE ||
erase.state == MTD_ERASE_FAILED);
if (ret) {
- dev_err(d->dev, "Interrupted erase block %#llx erassure on %s",
+ dev_err(d->dev, "Interrupted erase block %#llx erasure on %s\n",
erase.addr, mtd->name);
return -EINTR;
}
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7b7a887b4709..353a9ddf6b97 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -179,15 +179,6 @@ config MTD_NAND_S3C2410_DEBUG
help
Enable debugging of the S3C NAND driver
-config MTD_NAND_S3C2410_HWECC
- bool "Samsung S3C NAND Hardware ECC"
- depends on MTD_NAND_S3C2410
- help
- Enable the use of the controller's internal ECC generator when
- using NAND. Early versions of the chips have had problems with
- incorrect ECC generation, and if using these, the default of
- software ECC is preferable.
-
config MTD_NAND_NDFC
tristate "NDFC NanD Flash Controller"
depends on 4xx
@@ -205,6 +196,13 @@ config MTD_NAND_S3C2410_CLKSTOP
when the is NAND chip selected or released, but will save
approximately 5mA of power when there is nothing happening.
+config MTD_NAND_TANGO
+ tristate "NAND Flash support for Tango chips"
+ depends on ARCH_TANGO || COMPILE_TEST
+ depends on HAS_DMA
+ help
+ Enables the NAND Flash controller on Tango chips.
+
config MTD_NAND_DISKONCHIP
tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
depends on HAS_IOMEM
@@ -426,6 +424,11 @@ config MTD_NAND_ORION
No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
+config MTD_NAND_OXNAS
+ tristate "NAND Flash support for Oxford Semiconductor SoC"
+ help
+ This enables the NAND flash controller on Oxford Semiconductor SoCs.
+
config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers"
depends on FSL_SOC
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index cafde6f3d957..19a66e404d5b 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o
obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
+obj-$(CONFIG_MTD_NAND_TANGO) += tango_nand.o
obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
obj-$(CONFIG_MTD_NAND_DOCG4) += docg4.o
@@ -35,6 +36,7 @@ obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
+obj-$(CONFIG_MTD_NAND_OXNAS) += oxnas_nand.o
obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
index 78e12cc8bac2..5d6c26f3cf7f 100644
--- a/drivers/mtd/nand/ams-delta.c
+++ b/drivers/mtd/nand/ams-delta.c
@@ -234,10 +234,9 @@ static int ams_delta_init(struct platform_device *pdev)
goto out_gpio;
/* Scan to find existence of the device */
- if (nand_scan(ams_delta_mtd, 1)) {
- err = -ENXIO;
+ err = nand_scan(ams_delta_mtd, 1);
+ if (err)
goto out_mtd;
- }
/* Register the partitions */
mtd_device_register(ams_delta_mtd, partition_info,
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 68b9160108c9..9ebd5ecefea6 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -2267,10 +2267,9 @@ static int atmel_nand_probe(struct platform_device *pdev)
dev_info(host->dev, "No DMA support for NAND access.\n");
/* first scan to find the device and get the page size */
- if (nand_scan_ident(mtd, 1, NULL)) {
- res = -ENXIO;
+ res = nand_scan_ident(mtd, 1, NULL);
+ if (res)
goto err_scan_ident;
- }
if (host->board.on_flash_bbt || on_flash_bbt)
nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
@@ -2304,10 +2303,9 @@ static int atmel_nand_probe(struct platform_device *pdev)
}
/* second phase scan */
- if (nand_scan_tail(mtd)) {
- res = -ENXIO;
+ res = nand_scan_tail(mtd);
+ if (res)
goto err_scan_tail;
- }
mtd->name = "atmel_nand";
res = mtd_device_register(mtd, host->board.parts,
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
index 9d2424bfdbf5..42ebd73f821d 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
@@ -2209,8 +2209,9 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
nand_writereg(ctrl, cfg_offs,
nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
- if (nand_scan_ident(mtd, 1, NULL))
- return -ENXIO;
+ ret = nand_scan_ident(mtd, 1, NULL);
+ if (ret)
+ return ret;
chip->options |= NAND_NO_SUBPAGE_WRITE;
/*
@@ -2234,8 +2235,9 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
if (ret)
return ret;
- if (nand_scan_tail(mtd))
- return -ENXIO;
+ ret = nand_scan_tail(mtd);
+ if (ret)
+ return ret;
return mtd_device_register(mtd, NULL, 0);
}
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index 0b0c93702abb..d40c32d311d8 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -725,10 +725,9 @@ static int cafe_nand_probe(struct pci_dev *pdev,
usedma = 0;
/* Scan to find existence of the device */
- if (nand_scan_ident(mtd, 2, NULL)) {
- err = -ENXIO;
+ err = nand_scan_ident(mtd, 2, NULL);
+ if (err)
goto out_irq;
- }
cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev,
2112 + sizeof(struct nand_buffers) +
diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c
index 49133783ca53..226ac0bcafc6 100644
--- a/drivers/mtd/nand/cmx270_nand.c
+++ b/drivers/mtd/nand/cmx270_nand.c
@@ -195,9 +195,9 @@ static int __init cmx270_init(void)
this->write_buf = cmx270_write_buf;
/* Scan to find existence of the device */
- if (nand_scan (cmx270_nand_mtd, 1)) {
+ ret = nand_scan(cmx270_nand_mtd, 1);
+ if (ret) {
pr_notice("No NAND device\n");
- ret = -ENXIO;
goto err_scan;
}
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c
index a65e4e0f57a1..594b28684138 100644
--- a/drivers/mtd/nand/cs553x_nand.c
+++ b/drivers/mtd/nand/cs553x_nand.c
@@ -242,10 +242,9 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
}
/* Scan to find existence of the device */
- if (nand_scan(new_mtd, 1)) {
- err = -ENXIO;
+ err = nand_scan(new_mtd, 1);
+ if (err)
goto out_free;
- }
cs553x_mtd[cs] = new_mtd;
goto out;
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 0476ae8776d9..73b9d4e2dca0 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -21,7 +21,6 @@
#include <linux/dma-mapping.h>
#include <linux/wait.h>
#include <linux/mutex.h>
-#include <linux/slab.h>
#include <linux/mtd/mtd.h>
#include <linux/module.h>
@@ -182,9 +181,6 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali)
{
int i;
- dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
- __FILE__, __LINE__, __func__);
-
for (i = 0; i < denali->max_banks; i++)
iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT,
denali->flash_reg + INTR_STATUS(i));
@@ -234,9 +230,6 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali,
uint16_t acc_clks;
uint16_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt;
- dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
- __FILE__, __LINE__, __func__);
-
en_lo = CEIL_DIV(Trp[mode], CLK_X);
en_hi = CEIL_DIV(Treh[mode], CLK_X);
#if ONFI_BLOOM_TIME
@@ -403,7 +396,7 @@ static void get_hynix_nand_para(struct denali_nand_info *denali,
break;
default:
dev_warn(denali->dev,
- "Spectra: Unknown Hynix NAND (Device ID: 0x%x).\n"
+ "Unknown Hynix NAND (Device ID: 0x%x).\n"
"Will use default parameter values instead.\n",
device_id);
}
@@ -474,33 +467,6 @@ static void detect_max_banks(struct denali_nand_info *denali)
denali->max_banks = 1 << (features & FEATURES__N_BANKS);
}
-static void detect_partition_feature(struct denali_nand_info *denali)
-{
- /*
- * For MRST platform, denali->fwblks represent the
- * number of blocks firmware is taken,
- * FW is in protect partition and MTD driver has no
- * permission to access it. So let driver know how many
- * blocks it can't touch.
- */
- if (ioread32(denali->flash_reg + FEATURES) & FEATURES__PARTITION) {
- if ((ioread32(denali->flash_reg + PERM_SRC_ID(1)) &
- PERM_SRC_ID__SRCID) == SPECTRA_PARTITION_ID) {
- denali->fwblks =
- ((ioread32(denali->flash_reg + MIN_MAX_BANK(1)) &
- MIN_MAX_BANK__MIN_VALUE) *
- denali->blksperchip)
- +
- (ioread32(denali->flash_reg + MIN_BLK_ADDR(1)) &
- MIN_BLK_ADDR__VALUE);
- } else {
- denali->fwblks = SPECTRA_START_BLOCK;
- }
- } else {
- denali->fwblks = SPECTRA_START_BLOCK;
- }
-}
-
static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
{
uint16_t status = PASS;
@@ -508,9 +474,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
uint8_t maf_id, device_id;
int i;
- dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
- __FILE__, __LINE__, __func__);
-
/*
* Use read id method to get device ID and other params.
* For some NAND chips, controller can't report the correct
@@ -552,8 +515,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
find_valid_banks(denali);
- detect_partition_feature(denali);
-
/*
* If the user specified to override the default timings
* with a specific ONFI mode, we apply those changes here.
@@ -567,9 +528,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
static void denali_set_intr_modes(struct denali_nand_info *denali,
uint16_t INT_ENABLE)
{
- dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
- __FILE__, __LINE__, __func__);
-
if (INT_ENABLE)
iowrite32(1, denali->flash_reg + GLOBAL_INT_ENABLE);
else
@@ -605,7 +563,6 @@ static void denali_irq_init(struct denali_nand_info *denali)
static void denali_irq_cleanup(int irqnum, struct denali_nand_info *denali)
{
denali_set_intr_modes(denali, false);
- free_irq(irqnum, denali);
}
static void denali_irq_enable(struct denali_nand_info *denali,
@@ -1437,9 +1394,6 @@ static struct nand_bbt_descr bbt_mirror_descr = {
/* initialize driver data structures */
static void denali_drv_init(struct denali_nand_info *denali)
{
- denali->idx = 0;
-
- /* setup interrupt handler */
/*
* the completion object will be used to notify
* the callee that the interrupt is done
@@ -1485,14 +1439,12 @@ int denali_init(struct denali_nand_info *denali)
denali_hw_init(denali);
denali_drv_init(denali);
- /*
- * denali_isr register is done after all the hardware
- * initilization is finished
- */
- if (request_irq(denali->irq, denali_isr, IRQF_SHARED,
- DENALI_NAND_NAME, denali)) {
- pr_err("Spectra: Unable to allocate IRQ\n");
- return -ENODEV;
+ /* Request IRQ after all the hardware initialization is finished */
+ ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
+ IRQF_SHARED, DENALI_NAND_NAME, denali);
+ if (ret) {
+ dev_err(denali->dev, "Unable to request IRQ\n");
+ return ret;
}
/* now that our ISR is registered, we can enable interrupts */
@@ -1510,10 +1462,9 @@ int denali_init(struct denali_nand_info *denali)
* this is the first stage in a two step process to register
* with the nand subsystem
*/
- if (nand_scan_ident(mtd, denali->max_banks, NULL)) {
- ret = -ENXIO;
+ ret = nand_scan_ident(mtd, denali->max_banks, NULL);
+ if (ret)
goto failed_req_irq;
- }
/* allocate the right size buffer now */
devm_kfree(denali->dev, denali->buf.buf);
@@ -1528,7 +1479,7 @@ int denali_init(struct denali_nand_info *denali)
/* Is 32-bit DMA supported? */
ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32));
if (ret) {
- pr_err("Spectra: no usable DMA configuration\n");
+ dev_err(denali->dev, "No usable DMA configuration\n");
goto failed_req_irq;
}
@@ -1536,7 +1487,7 @@ int denali_init(struct denali_nand_info *denali)
mtd->writesize + mtd->oobsize,
DMA_BIDIRECTIONAL);
if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) {
- dev_err(denali->dev, "Spectra: failed to map DMA buffer\n");
+ dev_err(denali->dev, "Failed to map DMA buffer\n");
ret = -EIO;
goto failed_req_irq;
}
@@ -1547,16 +1498,16 @@ int denali_init(struct denali_nand_info *denali)
* the real pagesize and anything necessery
*/
denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED);
- denali->nand.chipsize <<= (denali->devnum - 1);
- denali->nand.page_shift += (denali->devnum - 1);
+ denali->nand.chipsize <<= denali->devnum - 1;
+ denali->nand.page_shift += denali->devnum - 1;
denali->nand.pagemask = (denali->nand.chipsize >>
denali->nand.page_shift) - 1;
- denali->nand.bbt_erase_shift += (denali->devnum - 1);
+ denali->nand.bbt_erase_shift += denali->devnum - 1;
denali->nand.phys_erase_shift = denali->nand.bbt_erase_shift;
- denali->nand.chip_shift += (denali->devnum - 1);
- mtd->writesize <<= (denali->devnum - 1);
- mtd->oobsize <<= (denali->devnum - 1);
- mtd->erasesize <<= (denali->devnum - 1);
+ denali->nand.chip_shift += denali->devnum - 1;
+ mtd->writesize <<= denali->devnum - 1;
+ mtd->oobsize <<= denali->devnum - 1;
+ mtd->erasesize <<= denali->devnum - 1;
mtd->size = denali->nand.numchips * denali->nand.chipsize;
denali->bbtskipbytes *= denali->devnum;
@@ -1606,14 +1557,6 @@ int denali_init(struct denali_nand_info *denali)
denali->nand.ecc.bytes *= denali->devnum;
denali->nand.ecc.strength *= denali->devnum;
- /*
- * Let driver know the total blocks number and how many blocks
- * contained by each nand chip. blksperchip will help driver to
- * know how many blocks is taken by FW.
- */
- denali->totalblks = mtd->size >> denali->nand.phys_erase_shift;
- denali->blksperchip = denali->totalblks / denali->nand.numchips;
-
/* override the default read operations */
denali->nand.ecc.size = ECC_SECTOR_SIZE * denali->devnum;
denali->nand.ecc.read_page = denali_read_page;
@@ -1624,15 +1567,13 @@ int denali_init(struct denali_nand_info *denali)
denali->nand.ecc.write_oob = denali_write_oob;
denali->nand.erase = denali_erase;
- if (nand_scan_tail(mtd)) {
- ret = -ENXIO;
+ ret = nand_scan_tail(mtd);
+ if (ret)
goto failed_req_irq;
- }
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
- dev_err(denali->dev, "Spectra: Failed to register MTD: %d\n",
- ret);
+ dev_err(denali->dev, "Failed to register MTD: %d\n", ret);
goto failed_req_irq;
}
return 0;
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index e7ab4866a5da..ea22191e8515 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -383,14 +383,6 @@
#define CLK_X 5
#define CLK_MULTI 4
-/* spectraswconfig.h */
-#define CMD_DMA 0
-
-#define SPECTRA_PARTITION_ID 0
-/**** Block Table and Reserved Block Parameters *****/
-#define SPECTRA_START_BLOCK 3
-#define NUM_FREE_BLOCKS_GATE 30
-
/* KBV - Updated to LNW scratch register address */
#define SCRATCH_REG_ADDR CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR
#define SCRATCH_REG_SIZE 64
@@ -467,13 +459,9 @@ struct denali_nand_info {
spinlock_t irq_lock;
uint32_t irq_status;
int irq_debug_array[32];
- int idx;
int irq;
uint32_t devnum; /* represent how many nands connected */
- uint32_t fwblks; /* represent how many blocks FW used */
- uint32_t totalblks;
- uint32_t blksperchip;
uint32_t bbtskipbytes;
uint32_t max_banks;
};
diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c
index 0cb1e8d9fbfc..5607fcd3b8ed 100644
--- a/drivers/mtd/nand/denali_dt.c
+++ b/drivers/mtd/nand/denali_dt.c
@@ -21,7 +21,6 @@
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/slab.h>
#include "denali.h"
@@ -110,7 +109,7 @@ static int denali_dt_remove(struct platform_device *ofdev)
struct denali_dt *dt = platform_get_drvdata(ofdev);
denali_remove(&dt->denali);
- clk_disable(dt->clk);
+ clk_disable_unprepare(dt->clk);
return 0;
}
diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c
index de31514df282..ac843238b77e 100644
--- a/drivers/mtd/nand/denali_pci.c
+++ b/drivers/mtd/nand/denali_pci.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/slab.h>
#include "denali.h"
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index d4f454a4b35e..4924b43977ef 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -926,8 +926,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
/*
* Scan to find existence of the device
*/
- if (nand_scan_ident(mtd, 1, NULL)) {
- ret = -ENXIO;
+ ret = nand_scan_ident(mtd, 1, NULL);
+ if (ret) {
dev_err(&pdev->dev, "No NAND Device found!\n");
goto err_scan_ident;
}
@@ -992,10 +992,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
}
/* Second stage of scan to fill MTD data-structures */
- if (nand_scan_tail(mtd)) {
- ret = -ENXIO;
+ ret = nand_scan_tail(mtd);
+ if (ret)
goto err_probe;
- }
/*
* The partition information can is accessed by (in the same precedence)
diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c
index 6317f6836022..0d24857469ab 100644
--- a/drivers/mtd/nand/gpio.c
+++ b/drivers/mtd/nand/gpio.c
@@ -286,10 +286,9 @@ static int gpio_nand_probe(struct platform_device *pdev)
if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);
- if (nand_scan(mtd, 1)) {
- ret = -ENXIO;
+ ret = nand_scan(mtd, 1);
+ if (ret)
goto err_wp;
- }
if (gpiomtd->plat.adjust_parts)
gpiomtd->plat.adjust_parts(&gpiomtd->plat, mtd->size);
diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/hisi504_nand.c
index 9432546f4cd4..e40364eeb556 100644
--- a/drivers/mtd/nand/hisi504_nand.c
+++ b/drivers/mtd/nand/hisi504_nand.c
@@ -774,10 +774,8 @@ static int hisi_nfc_probe(struct platform_device *pdev)
}
ret = nand_scan_ident(mtd, max_chips, NULL);
- if (ret) {
- ret = -ENODEV;
+ if (ret)
goto err_res;
- }
host->buffer = dmam_alloc_coherent(dev, mtd->writesize + mtd->oobsize,
&host->dma_buffer, GFP_KERNEL);
diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c
index 852388171f20..5553a5d9efd1 100644
--- a/drivers/mtd/nand/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/lpc32xx_mlc.c
@@ -747,10 +747,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
* Scan to find existance of the device and
* Get the type of NAND device SMALL block or LARGE block
*/
- if (nand_scan_ident(mtd, 1, NULL)) {
- res = -ENXIO;
+ res = nand_scan_ident(mtd, 1, NULL);
+ if (res)
goto err_exit3;
- }
host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
if (!host->dma_buf) {
@@ -793,10 +792,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
* Fills out all the uninitialized function pointers with the defaults
* And scans for a bad block table if appropriate.
*/
- if (nand_scan_tail(mtd)) {
- res = -ENXIO;
+ res = nand_scan_tail(mtd);
+ if (res)
goto err_exit4;
- }
mtd->name = DRV_NAME;
diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c
index 8d3edc34958e..53bafe23ab39 100644
--- a/drivers/mtd/nand/lpc32xx_slc.c
+++ b/drivers/mtd/nand/lpc32xx_slc.c
@@ -894,10 +894,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
}
/* Find NAND device */
- if (nand_scan_ident(mtd, 1, NULL)) {
- res = -ENXIO;
+ res = nand_scan_ident(mtd, 1, NULL);
+ if (res)
goto err_exit3;
- }
/* OOB and ECC CPU and DMA work areas */
host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
@@ -929,10 +928,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
/*
* Fills out all the uninitialized function pointers with the defaults
*/
- if (nand_scan_tail(mtd)) {
- res = -ENXIO;
+ res = nand_scan_tail(mtd);
+ if (res)
goto err_exit3;
- }
mtd->name = "nxp_lpc3220_slc";
res = mtd_device_register(mtd, host->ncfg->parts,
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
index 7eacb2f545f5..6d6eaed2d20c 100644
--- a/drivers/mtd/nand/mpc5121_nfc.c
+++ b/drivers/mtd/nand/mpc5121_nfc.c
@@ -777,9 +777,9 @@ static int mpc5121_nfc_probe(struct platform_device *op)
}
/* Detect NAND chips */
- if (nand_scan(mtd, be32_to_cpup(chips_no))) {
+ retval = nand_scan(mtd, be32_to_cpup(chips_no));
+ if (retval) {
dev_err(dev, "NAND Flash not found !\n");
- retval = -ENXIO;
goto error;
}
diff --git a/drivers/mtd/nand/mtk_nand.c b/drivers/mtd/nand/mtk_nand.c
index 5223a2182ee4..6c3eed3c2094 100644
--- a/drivers/mtd/nand/mtk_nand.c
+++ b/drivers/mtd/nand/mtk_nand.c
@@ -1297,7 +1297,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
ret = nand_scan_ident(mtd, nsels, NULL);
if (ret)
- return -ENODEV;
+ return ret;
/* store bbt magic in page, cause OOB is not protected */
if (nand->bbt_options & NAND_BBT_USE_FLASH)
@@ -1323,7 +1323,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
ret = nand_scan_tail(mtd);
if (ret)
- return -ENODEV;
+ return ret;
ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
if (ret) {
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index d7f724b24fd7..61ca020c5272 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -1747,10 +1747,9 @@ static int mxcnd_probe(struct platform_device *pdev)
}
/* first scan to find the device and get the page size */
- if (nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL)) {
- err = -ENXIO;
+ err = nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL);
+ if (err)
goto escan;
- }
switch (this->ecc.mode) {
case NAND_ECC_HW:
@@ -1808,10 +1807,9 @@ static int mxcnd_probe(struct platform_device *pdev)
}
/* second phase scan */
- if (nand_scan_tail(mtd)) {
- err = -ENXIO;
+ err = nand_scan_tail(mtd);
+ if (err)
goto escan;
- }
/* Register the partitions */
mtd_device_parse_register(mtd, part_probes,
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 3bde96a3f7bf..ec1c28aaaf23 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -709,6 +709,25 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
nand_wait_ready(mtd);
}
+static void nand_ccs_delay(struct nand_chip *chip)
+{
+ /*
+ * The controller already takes care of waiting for tCCS when the RNDIN
+ * or RNDOUT command is sent, return directly.
+ */
+ if (!(chip->options & NAND_WAIT_TCCS))
+ return;
+
+ /*
+ * Wait tCCS_min if it is correctly defined, otherwise wait 500ns
+ * (which should be safe for all NANDs).
+ */
+ if (chip->data_interface && chip->data_interface->timings.sdr.tCCS_min)
+ ndelay(chip->data_interface->timings.sdr.tCCS_min / 1000);
+ else
+ ndelay(500);
+}
+
/**
* nand_command_lp - [DEFAULT] Send command to NAND large page device
* @mtd: MTD device structure
@@ -773,10 +792,13 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
case NAND_CMD_ERASE1:
case NAND_CMD_ERASE2:
case NAND_CMD_SEQIN:
- case NAND_CMD_RNDIN:
case NAND_CMD_STATUS:
return;
+ case NAND_CMD_RNDIN:
+ nand_ccs_delay(chip);
+ return;
+
case NAND_CMD_RESET:
if (chip->dev_ready)
break;
@@ -795,6 +817,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
chip->cmd_ctrl(mtd, NAND_CMD_NONE,
NAND_NCE | NAND_CTRL_CHANGE);
+
+ nand_ccs_delay(chip);
return;
case NAND_CMD_READ0:
@@ -1946,7 +1970,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
__func__, buf);
read_retry:
- chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+ if (nand_standard_page_accessors(&chip->ecc))
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
/*
* Now read the page into the buffer. Absent an error,
@@ -2634,7 +2659,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
else
subpage = 0;
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+ if (nand_standard_page_accessors(&chip->ecc))
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
if (unlikely(raw))
status = chip->ecc.write_page_raw(mtd, chip, buf,
@@ -2657,7 +2683,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
if (!cached || !NAND_HAS_CACHEPROG(chip)) {
- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ if (nand_standard_page_accessors(&chip->ecc))
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
/*
* See if operation failed and additional status checks are
@@ -3985,10 +4012,9 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
/*
* Get the flash and manufacturer id and lookup if the type is supported.
*/
-static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
- struct nand_chip *chip,
- int *maf_id, int *dev_id,
- struct nand_flash_dev *type)
+static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
+ int *maf_id, int *dev_id,
+ struct nand_flash_dev *type)
{
int busw;
int i, maf_idx;
@@ -4026,7 +4052,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
*maf_id, *dev_id, id_data[0], id_data[1]);
- return ERR_PTR(-ENODEV);
+ return -ENODEV;
}
if (!type)
@@ -4053,7 +4079,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
}
if (!type->name)
- return ERR_PTR(-ENODEV);
+ return -ENODEV;
if (!mtd->name)
mtd->name = type->name;
@@ -4098,7 +4124,7 @@ ident_done:
pr_warn("bus width %d instead %d bit\n",
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
busw ? 16 : 8);
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
nand_decode_bbm_options(mtd, chip, id_data);
@@ -4140,7 +4166,7 @@ ident_done:
pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
- return type;
+ return 0;
}
static const char * const nand_ecc_modes[] = {
@@ -4306,7 +4332,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
{
int i, nand_maf_id, nand_dev_id;
struct nand_chip *chip = mtd_to_nand(mtd);
- struct nand_flash_dev *type;
int ret;
ret = nand_dt_init(chip);
@@ -4329,14 +4354,12 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
/* Read the flash type */
- type = nand_get_flash_type(mtd, chip, &nand_maf_id,
- &nand_dev_id, table);
-
- if (IS_ERR(type)) {
+ ret = nand_get_flash_type(mtd, chip, &nand_maf_id, &nand_dev_id, table);
+ if (ret) {
if (!(chip->options & NAND_SCAN_SILENT_NODEV))
pr_warn("No NAND device found\n");
chip->select_chip(mtd, -1);
- return PTR_ERR(type);
+ return ret;
}
/* Initialize the ->data_interface field. */
@@ -4515,6 +4538,26 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds;
}
+static bool invalid_ecc_page_accessors(struct nand_chip *chip)
+{
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+ if (nand_standard_page_accessors(ecc))
+ return false;
+
+ /*
+ * NAND_ECC_CUSTOM_PAGE_ACCESS flag is set, make sure the NAND
+ * controller driver implements all the page accessors because
+ * default helpers are not suitable when the core does not
+ * send the READ0/PAGEPROG commands.
+ */
+ return (!ecc->read_page || !ecc->write_page ||
+ !ecc->read_page_raw || !ecc->write_page_raw ||
+ (NAND_HAS_SUBPAGE_READ(chip) && !ecc->read_subpage) ||
+ (NAND_HAS_SUBPAGE_WRITE(chip) && !ecc->write_subpage &&
+ ecc->hwctl && ecc->calculate));
+}
+
/**
* nand_scan_tail - [NAND Interface] Scan for the NAND device
* @mtd: MTD device structure
@@ -4535,6 +4578,11 @@ int nand_scan_tail(struct mtd_info *mtd)
!(chip->bbt_options & NAND_BBT_USE_FLASH)))
return -EINVAL;
+ if (invalid_ecc_page_accessors(chip)) {
+ pr_err("Invalid ECC page accessors setup\n");
+ return -EINVAL;
+ }
+
if (!(chip->options & NAND_OWN_BUFFERS)) {
nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize
+ mtd->oobsize * 3, GFP_KERNEL);
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 2af9869a115e..b3a332f37e14 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -36,6 +36,9 @@ struct nand_flash_dev nand_flash_ids[] = {
{"TC58NVG2S0F 4G 3.3V 8-bit",
{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
+ {"TC58NVG2S0H 4G 3.3V 8-bit",
+ { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x16, 0x08, 0x00} },
+ SZ_4K, SZ_512, SZ_256K, 0, 8, 256, NAND_ECC_INFO(8, SZ_512) },
{"TC58NVG3S0F 8G 3.3V 8-bit",
{ .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} },
SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) },
diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c
index 13a587407be3..f06312df3669 100644
--- a/drivers/mtd/nand/nand_timings.c
+++ b/drivers/mtd/nand/nand_timings.c
@@ -18,6 +18,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
{
.type = NAND_SDR_IFACE,
.timings.sdr = {
+ .tCCS_min = 500000,
+ .tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 20000,
.tALS_min = 50000,
@@ -58,6 +60,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
{
.type = NAND_SDR_IFACE,
.timings.sdr = {
+ .tCCS_min = 500000,
+ .tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 10000,
.tALS_min = 25000,
@@ -98,6 +102,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
{
.type = NAND_SDR_IFACE,
.timings.sdr = {
+ .tCCS_min = 500000,
+ .tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 10000,
.tALS_min = 15000,
@@ -138,6 +144,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
{
.type = NAND_SDR_IFACE,
.timings.sdr = {
+ .tCCS_min = 500000,
+ .tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 5000,
.tALS_min = 10000,
@@ -178,6 +186,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
{
.type = NAND_SDR_IFACE,
.timings.sdr = {
+ .tCCS_min = 500000,
+ .tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 5000,
.tALS_min = 10000,
@@ -218,6 +228,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
{
.type = NAND_SDR_IFACE,
.timings.sdr = {
+ .tCCS_min = 500000,
+ .tR_max = 200000000,
.tADL_min = 400000,
.tALH_min = 5000,
.tALS_min = 10000,
@@ -290,10 +302,22 @@ int onfi_init_data_interface(struct nand_chip *chip,
*iface = onfi_sdr_timings[timing_mode];
/*
- * TODO: initialize timings that cannot be deduced from timing mode:
+ * Initialize timings that cannot be deduced from timing mode:
* tR, tPROG, tCCS, ...
* These information are part of the ONFI parameter page.
*/
+ if (chip->onfi_version) {
+ struct nand_onfi_params *params = &chip->onfi_params;
+ struct nand_sdr_timings *timings = &iface->timings.sdr;
+
+ /* microseconds -> picoseconds */
+ timings->tPROG_max = 1000000UL * le16_to_cpu(params->t_prog);
+ timings->tBERS_max = 1000000UL * le16_to_cpu(params->t_bers);
+ timings->tR_max = 1000000UL * le16_to_cpu(params->t_r);
+
+ /* nanoseconds -> picoseconds */
+ timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs);
+ }
return 0;
}
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 1eb934414eb5..c84742671a5f 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -525,24 +525,20 @@ static int nandsim_debugfs_create(struct nandsim *dev)
{
struct nandsim_debug_info *dbg = &dev->dbg;
struct dentry *dent;
- int err;
if (!IS_ENABLED(CONFIG_DEBUG_FS))
return 0;
dent = debugfs_create_dir("nandsim", NULL);
- if (IS_ERR_OR_NULL(dent)) {
- int err = dent ? -ENODEV : PTR_ERR(dent);
-
- NS_ERR("cannot create \"nandsim\" debugfs directory, err %d\n",
- err);
- return err;
+ if (!dent) {
+ NS_ERR("cannot create \"nandsim\" debugfs directory\n");
+ return -ENODEV;
}
dbg->dfs_root = dent;
dent = debugfs_create_file("wear_report", S_IRUSR,
dbg->dfs_root, dev, &dfs_fops);
- if (IS_ERR_OR_NULL(dent))
+ if (!dent)
goto out_remove;
dbg->dfs_wear_report = dent;
@@ -550,8 +546,7 @@ static int nandsim_debugfs_create(struct nandsim *dev)
out_remove:
debugfs_remove_recursive(dbg->dfs_root);
- err = dent ? PTR_ERR(dent) : -ENODEV;
- return err;
+ return -ENODEV;
}
/**
@@ -2313,8 +2308,6 @@ static int __init ns_init_module(void)
retval = nand_scan_ident(nsmtd, 1, NULL);
if (retval) {
NS_ERR("cannot scan NAND Simulator device\n");
- if (retval > 0)
- retval = -ENXIO;
goto error;
}
@@ -2350,8 +2343,6 @@ static int __init ns_init_module(void)
retval = nand_scan_tail(nsmtd);
if (retval) {
NS_ERR("can't register NAND Simulator\n");
- if (retval > 0)
- retval = -ENXIO;
goto error;
}
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 5513bfd9cdc9..2a52101120d4 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -1895,10 +1895,10 @@ static int omap_nand_probe(struct platform_device *pdev)
/* scan NAND device connected to chip controller */
nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
- if (nand_scan_ident(mtd, 1, NULL)) {
+ err = nand_scan_ident(mtd, 1, NULL);
+ if (err) {
dev_err(&info->pdev->dev,
"scan failed, may be bus-width mismatch\n");
- err = -ENXIO;
goto return_error;
}
@@ -2154,10 +2154,9 @@ static int omap_nand_probe(struct platform_device *pdev)
scan_tail:
/* second phase scan */
- if (nand_scan_tail(mtd)) {
- err = -ENXIO;
+ err = nand_scan_tail(mtd);
+ if (err)
goto return_error;
- }
if (dev->of_node)
mtd_device_register(mtd, NULL, 0);
@@ -2197,6 +2196,7 @@ static const struct of_device_id omap_nand_ids[] = {
{ .compatible = "ti,omap2-nand", },
{},
};
+MODULE_DEVICE_TABLE(of, omap_nand_ids);
static struct platform_driver omap_nand_driver = {
.probe = omap_nand_probe,
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
index 40a7c4a2cf0d..4a91c5d000be 100644
--- a/drivers/mtd/nand/orion_nand.c
+++ b/drivers/mtd/nand/orion_nand.c
@@ -155,10 +155,9 @@ static int __init orion_nand_probe(struct platform_device *pdev)
clk_put(clk);
}
- if (nand_scan(mtd, 1)) {
- ret = -ENXIO;
+ ret = nand_scan(mtd, 1);
+ if (ret)
goto no_dev;
- }
mtd->name = "orion_nand";
ret = mtd_device_register(mtd, board->parts, board->nr_parts);
diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
new file mode 100644
index 000000000000..3e3bf3b364d2
--- /dev/null
+++ b/drivers/mtd/nand/oxnas_nand.c
@@ -0,0 +1,195 @@
+/*
+ * Oxford Semiconductor OXNAS NAND driver
+
+ * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
+ * Heavily based on plat_nand.c :
+ * Author: Vitaly Wool <vitalywool@gmail.com>
+ * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
+ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+
+/* Nand commands */
+#define OXNAS_NAND_CMD_ALE BIT(18)
+#define OXNAS_NAND_CMD_CLE BIT(19)
+
+#define OXNAS_NAND_MAX_CHIPS 1
+
+struct oxnas_nand_ctrl {
+ struct nand_hw_control base;
+ void __iomem *io_base;
+ struct clk *clk;
+ struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
+};
+
+static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+ return readb(oxnas->io_base);
+}
+
+static void oxnas_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+ ioread8_rep(oxnas->io_base, buf, len);
+}
+
+static void oxnas_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+ iowrite8_rep(oxnas->io_base, buf, len);
+}
+
+/* Single CS command control */
+static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+ if (ctrl & NAND_CLE)
+ writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_CLE);
+ else if (ctrl & NAND_ALE)
+ writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_ALE);
+}
+
+/*
+ * Probe for the NAND device.
+ */
+static int oxnas_nand_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *nand_np;
+ struct oxnas_nand_ctrl *oxnas;
+ struct nand_chip *chip;
+ struct mtd_info *mtd;
+ struct resource *res;
+ int nchips = 0;
+ int count = 0;
+ int err = 0;
+
+ /* Allocate memory for the device structure (and zero it) */
+ oxnas = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
+ GFP_KERNEL);
+ if (!oxnas)
+ return -ENOMEM;
+
+ nand_hw_control_init(&oxnas->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ oxnas->io_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(oxnas->io_base))
+ return PTR_ERR(oxnas->io_base);
+
+ oxnas->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(oxnas->clk))
+ oxnas->clk = NULL;
+
+ /* Only a single chip node is supported */
+ count = of_get_child_count(np);
+ if (count > 1)
+ return -EINVAL;
+
+ clk_prepare_enable(oxnas->clk);
+ device_reset_optional(&pdev->dev);
+
+ for_each_child_of_node(np, nand_np) {
+ chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
+ GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->controller = &oxnas->base;
+
+ nand_set_flash_node(chip, nand_np);
+ nand_set_controller_data(chip, oxnas);
+
+ mtd = nand_to_mtd(chip);
+ mtd->dev.parent = &pdev->dev;
+ mtd->priv = chip;
+
+ chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
+ chip->read_buf = oxnas_nand_read_buf;
+ chip->read_byte = oxnas_nand_read_byte;
+ chip->write_buf = oxnas_nand_write_buf;
+ chip->chip_delay = 30;
+
+ /* Scan to find existence of the device */
+ err = nand_scan(mtd, 1);
+ if (err)
+ return err;
+
+ err = mtd_device_register(mtd, NULL, 0);
+ if (err) {
+ nand_release(mtd);
+ return err;
+ }
+
+ oxnas->chips[nchips] = chip;
+ ++nchips;
+ }
+
+ /* Exit if no chips found */
+ if (!nchips)
+ return -ENODEV;
+
+ platform_set_drvdata(pdev, oxnas);
+
+ return 0;
+}
+
+static int oxnas_nand_remove(struct platform_device *pdev)
+{
+ struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev);
+
+ if (oxnas->chips[0])
+ nand_release(nand_to_mtd(oxnas->chips[0]));
+
+ clk_disable_unprepare(oxnas->clk);
+
+ return 0;
+}
+
+static const struct of_device_id oxnas_nand_match[] = {
+ { .compatible = "oxsemi,ox820-nand" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, oxnas_nand_match);
+
+static struct platform_driver oxnas_nand_driver = {
+ .probe = oxnas_nand_probe,
+ .remove = oxnas_nand_remove,
+ .driver = {
+ .name = "oxnas_nand",
+ .of_match_table = oxnas_nand_match,
+ },
+};
+
+module_platform_driver(oxnas_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_DESCRIPTION("Oxnas NAND driver");
+MODULE_ALIAS("platform:oxnas_nand");
diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c
index 5de7591b0510..074b8b01289e 100644
--- a/drivers/mtd/nand/pasemi_nand.c
+++ b/drivers/mtd/nand/pasemi_nand.c
@@ -156,10 +156,9 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
chip->bbt_options = NAND_BBT_USE_FLASH;
/* Scan to find existence of the device */
- if (nand_scan(pasemi_nand_mtd, 1)) {
- err = -ENXIO;
+ err = nand_scan(pasemi_nand_mtd, 1);
+ if (err)
goto out_lpc;
- }
if (mtd_device_register(pasemi_nand_mtd, NULL, 0)) {
dev_err(dev, "Unable to register MTD device\n");
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
index 415a53a0deeb..791de3e4bbb6 100644
--- a/drivers/mtd/nand/plat_nand.c
+++ b/drivers/mtd/nand/plat_nand.c
@@ -86,10 +86,9 @@ static int plat_nand_probe(struct platform_device *pdev)
}
/* Scan to find existence of the device */
- if (nand_scan(mtd, pdata->chip.nr_chips)) {
- err = -ENXIO;
+ err = nand_scan(mtd, pdata->chip.nr_chips);
+ if (err)
goto out;
- }
part_types = pdata->chip.part_probe_types;
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index b121bf4ed73a..649ba8200832 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -1680,8 +1680,9 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
chip->ecc.strength = pdata->ecc_strength;
chip->ecc.size = pdata->ecc_step_size;
- if (nand_scan_ident(mtd, 1, NULL))
- return -ENODEV;
+ ret = nand_scan_ident(mtd, 1, NULL);
+ if (ret)
+ return ret;
if (!pdata->keep_config) {
ret = pxa3xx_nand_init(host);
@@ -1774,8 +1775,11 @@ static int alloc_nand_resource(struct platform_device *pdev)
int ret, irq, cs;
pdata = dev_get_platdata(&pdev->dev);
- if (pdata->num_cs <= 0)
+ if (pdata->num_cs <= 0) {
+ dev_err(&pdev->dev, "invalid number of chip selects\n");
return -ENODEV;
+ }
+
info = devm_kzalloc(&pdev->dev,
sizeof(*info) + sizeof(*host) * pdata->num_cs,
GFP_KERNEL);
@@ -1813,8 +1817,9 @@ static int alloc_nand_resource(struct platform_device *pdev)
nand_hw_control_init(chip->controller);
info->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(info->clk)) {
- dev_err(&pdev->dev, "failed to get nand clock\n");
- return PTR_ERR(info->clk);
+ ret = PTR_ERR(info->clk);
+ dev_err(&pdev->dev, "failed to get nand clock: %d\n", ret);
+ return ret;
}
ret = clk_prepare_enable(info->clk);
if (ret < 0)
@@ -1842,6 +1847,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
info->mmio_base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(info->mmio_base)) {
ret = PTR_ERR(info->mmio_base);
+ dev_err(&pdev->dev, "failed to map register space: %d\n", ret);
goto fail_disable_clk;
}
info->mmio_phys = r->start;
@@ -1861,7 +1867,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
pxa3xx_nand_irq_thread, IRQF_ONESHOT,
pdev->name, info);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to request IRQ\n");
+ dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret);
goto fail_free_buf;
}
@@ -1960,10 +1966,8 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
}
ret = alloc_nand_resource(pdev);
- if (ret) {
- dev_err(&pdev->dev, "alloc nand resource failed\n");
+ if (ret)
return ret;
- }
info = platform_get_drvdata(pdev);
probe_success = 0;
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index d459c19d78de..f0b030d44f71 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -39,6 +39,8 @@
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
@@ -185,6 +187,22 @@ struct s3c2410_nand_info {
#endif
};
+struct s3c24XX_nand_devtype_data {
+ enum s3c_cpu_type type;
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
+ .type = TYPE_S3C2410,
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
+ .type = TYPE_S3C2412,
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
+ .type = TYPE_S3C2440,
+};
+
/* conversion functions */
static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
@@ -497,7 +515,6 @@ static int s3c2412_nand_devready(struct mtd_info *mtd)
/* ECC handling functions */
-#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
@@ -649,7 +666,6 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
return 0;
}
-#endif
/* over-ride the standard functions for a little more speed. We can
* use read/write block to move the data buffers to/from the controller
@@ -796,6 +812,30 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
return -ENODEV;
}
+static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd,
+ const struct nand_data_interface *conf,
+ bool check_only)
+{
+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ struct s3c2410_platform_nand *pdata = info->platform;
+ const struct nand_sdr_timings *timings;
+ int tacls;
+
+ timings = nand_get_sdr_timings(conf);
+ if (IS_ERR(timings))
+ return -ENOTSUPP;
+
+ tacls = timings->tCLS_min - timings->tWP_min;
+ if (tacls < 0)
+ tacls = 0;
+
+ pdata->tacls = DIV_ROUND_UP(tacls, 1000);
+ pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
+ pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);
+
+ return s3c2410_nand_setrate(info);
+}
+
/**
* s3c2410_nand_init_chip - initialise a single instance of an chip
* @info: The base NAND controller the chip is on.
@@ -810,9 +850,12 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
struct s3c2410_nand_mtd *nmtd,
struct s3c2410_nand_set *set)
{
+ struct device_node *np = info->device->of_node;
struct nand_chip *chip = &nmtd->chip;
void __iomem *regs = info->regs;
+ nand_set_flash_node(chip, set->of_node);
+
chip->write_buf = s3c2410_nand_write_buf;
chip->read_buf = s3c2410_nand_read_buf;
chip->select_chip = s3c2410_nand_select_chip;
@@ -821,6 +864,13 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
chip->options = set->options;
chip->controller = &info->controller;
+ /*
+ * let's keep behavior unchanged for legacy boards booting via pdata and
+ * auto-detect timings only when booting with a device tree.
+ */
+ if (np)
+ chip->setup_data_interface = s3c2410_nand_setup_data_interface;
+
switch (info->cpu_type) {
case TYPE_S3C2410:
chip->IO_ADDR_W = regs + S3C2410_NFDATA;
@@ -858,58 +908,14 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
nmtd->info = info;
nmtd->set = set;
-#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
- chip->ecc.calculate = s3c2410_nand_calculate_ecc;
- chip->ecc.correct = s3c2410_nand_correct_data;
- chip->ecc.mode = NAND_ECC_HW;
- chip->ecc.strength = 1;
+ chip->ecc.mode = info->platform->ecc_mode;
- switch (info->cpu_type) {
- case TYPE_S3C2410:
- chip->ecc.hwctl = s3c2410_nand_enable_hwecc;
- chip->ecc.calculate = s3c2410_nand_calculate_ecc;
- break;
-
- case TYPE_S3C2412:
- chip->ecc.hwctl = s3c2412_nand_enable_hwecc;
- chip->ecc.calculate = s3c2412_nand_calculate_ecc;
- break;
-
- case TYPE_S3C2440:
- chip->ecc.hwctl = s3c2440_nand_enable_hwecc;
- chip->ecc.calculate = s3c2440_nand_calculate_ecc;
- break;
- }
-#else
- chip->ecc.mode = NAND_ECC_SOFT;
- chip->ecc.algo = NAND_ECC_HAMMING;
-#endif
-
- if (set->disable_ecc)
- chip->ecc.mode = NAND_ECC_NONE;
-
- switch (chip->ecc.mode) {
- case NAND_ECC_NONE:
- dev_info(info->device, "NAND ECC disabled\n");
- break;
- case NAND_ECC_SOFT:
- dev_info(info->device, "NAND soft ECC\n");
- break;
- case NAND_ECC_HW:
- dev_info(info->device, "NAND hardware ECC\n");
- break;
- default:
- dev_info(info->device, "NAND ECC UNKNOWN\n");
- break;
- }
-
- /* If you use u-boot BBT creation code, specifying this flag will
- * let the kernel fish out the BBT from the NAND, and also skip the
- * full NAND scan that can take 1/2s or so. Little things... */
- if (set->flash_bbt) {
+ /*
+ * If you use u-boot BBT creation code, specifying this flag will
+ * let the kernel fish out the BBT from the NAND.
+ */
+ if (set->flash_bbt)
chip->bbt_options |= NAND_BBT_USE_FLASH;
- chip->options |= NAND_SKIP_BBTSCAN;
- }
}
/**
@@ -923,28 +929,146 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
*
* The internal state is currently limited to the ECC state information.
*/
-static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
- struct s3c2410_nand_mtd *nmtd)
+static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
+ struct s3c2410_nand_mtd *nmtd)
{
struct nand_chip *chip = &nmtd->chip;
- dev_dbg(info->device, "chip %p => page shift %d\n",
- chip, chip->page_shift);
+ switch (chip->ecc.mode) {
- if (chip->ecc.mode != NAND_ECC_HW)
- return;
+ case NAND_ECC_NONE:
+ dev_info(info->device, "ECC disabled\n");
+ break;
+
+ case NAND_ECC_SOFT:
+ /*
+ * This driver expects Hamming based ECC when ecc_mode is set
+ * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
+ * avoid adding an extra ecc_algo field to
+ * s3c2410_platform_nand.
+ */
+ chip->ecc.algo = NAND_ECC_HAMMING;
+ dev_info(info->device, "soft ECC\n");
+ break;
+
+ case NAND_ECC_HW:
+ chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+ chip->ecc.correct = s3c2410_nand_correct_data;
+ chip->ecc.strength = 1;
+
+ switch (info->cpu_type) {
+ case TYPE_S3C2410:
+ chip->ecc.hwctl = s3c2410_nand_enable_hwecc;
+ chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+ break;
+
+ case TYPE_S3C2412:
+ chip->ecc.hwctl = s3c2412_nand_enable_hwecc;
+ chip->ecc.calculate = s3c2412_nand_calculate_ecc;
+ break;
+
+ case TYPE_S3C2440:
+ chip->ecc.hwctl = s3c2440_nand_enable_hwecc;
+ chip->ecc.calculate = s3c2440_nand_calculate_ecc;
+ break;
+ }
+
+ dev_dbg(info->device, "chip %p => page shift %d\n",
+ chip, chip->page_shift);
/* change the behaviour depending on whether we are using
* the large or small page nand device */
+ if (chip->page_shift > 10) {
+ chip->ecc.size = 256;
+ chip->ecc.bytes = 3;
+ } else {
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 3;
+ mtd_set_ooblayout(nand_to_mtd(chip),
+ &s3c2410_ooblayout_ops);
+ }
- if (chip->page_shift > 10) {
- chip->ecc.size = 256;
- chip->ecc.bytes = 3;
- } else {
- chip->ecc.size = 512;
- chip->ecc.bytes = 3;
- mtd_set_ooblayout(nand_to_mtd(chip), &s3c2410_ooblayout_ops);
+ dev_info(info->device, "hardware ECC\n");
+ break;
+
+ default:
+ dev_err(info->device, "invalid ECC mode!\n");
+ return -EINVAL;
}
+
+ if (chip->bbt_options & NAND_BBT_USE_FLASH)
+ chip->options |= NAND_SKIP_BBTSCAN;
+
+ return 0;
+}
+
+static const struct of_device_id s3c24xx_nand_dt_ids[] = {
+ {
+ .compatible = "samsung,s3c2410-nand",
+ .data = &s3c2410_nand_devtype_data,
+ }, {
+ /* also compatible with s3c6400 */
+ .compatible = "samsung,s3c2412-nand",
+ .data = &s3c2412_nand_devtype_data,
+ }, {
+ .compatible = "samsung,s3c2440-nand",
+ .data = &s3c2440_nand_devtype_data,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);
+
+static int s3c24xx_nand_probe_dt(struct platform_device *pdev)
+{
+ const struct s3c24XX_nand_devtype_data *devtype_data;
+ struct s3c2410_platform_nand *pdata;
+ struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
+ struct device_node *np = pdev->dev.of_node, *child;
+ struct s3c2410_nand_set *sets;
+
+ devtype_data = of_device_get_match_data(&pdev->dev);
+ if (!devtype_data)
+ return -ENODEV;
+
+ info->cpu_type = devtype_data->type;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdev->dev.platform_data = pdata;
+
+ pdata->nr_sets = of_get_child_count(np);
+ if (!pdata->nr_sets)
+ return 0;
+
+ sets = devm_kzalloc(&pdev->dev, sizeof(*sets) * pdata->nr_sets,
+ GFP_KERNEL);
+ if (!sets)
+ return -ENOMEM;
+
+ pdata->sets = sets;
+
+ for_each_available_child_of_node(np, child) {
+ sets->name = (char *)child->name;
+ sets->of_node = child;
+ sets->nr_chips = 1;
+
+ of_node_get(child);
+
+ sets++;
+ }
+
+ return 0;
+}
+
+static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)
+{
+ struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
+
+ info->cpu_type = platform_get_device_id(pdev)->driver_data;
+
+ return 0;
}
/* s3c24xx_nand_probe
@@ -956,8 +1080,7 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
*/
static int s3c24xx_nand_probe(struct platform_device *pdev)
{
- struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
- enum s3c_cpu_type cpu_type;
+ struct s3c2410_platform_nand *plat;
struct s3c2410_nand_info *info;
struct s3c2410_nand_mtd *nmtd;
struct s3c2410_nand_set *sets;
@@ -967,8 +1090,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
int nr_sets;
int setno;
- cpu_type = platform_get_device_id(pdev)->driver_data;
-
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (info == NULL) {
err = -ENOMEM;
@@ -990,6 +1111,16 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
+ if (pdev->dev.of_node)
+ err = s3c24xx_nand_probe_dt(pdev);
+ else
+ err = s3c24xx_nand_probe_pdata(pdev);
+
+ if (err)
+ goto exit_error;
+
+ plat = to_nand_plat(pdev);
+
/* allocate and map the resource */
/* currently we assume we have the one resource */
@@ -998,7 +1129,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
info->device = &pdev->dev;
info->platform = plat;
- info->cpu_type = cpu_type;
info->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(info->regs)) {
@@ -1008,12 +1138,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
- /* initialise the hardware */
-
- err = s3c2410_nand_inithw(info);
- if (err != 0)
- goto exit_error;
-
sets = (plat != NULL) ? plat->sets : NULL;
nr_sets = (plat != NULL) ? plat->nr_sets : 1;
@@ -1046,7 +1170,9 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
NULL);
if (nmtd->scan_res == 0) {
- s3c2410_nand_update_chip(info, nmtd);
+ err = s3c2410_nand_update_chip(info, nmtd);
+ if (err < 0)
+ goto exit_error;
nand_scan_tail(mtd);
s3c2410_nand_add_partition(info, nmtd, sets);
}
@@ -1055,6 +1181,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
sets++;
}
+ /* initialise the hardware */
+ err = s3c2410_nand_inithw(info);
+ if (err != 0)
+ goto exit_error;
+
err = s3c2410_nand_cpufreq_register(info);
if (err < 0) {
dev_err(&pdev->dev, "failed to init cpufreq support\n");
@@ -1155,6 +1286,7 @@ static struct platform_driver s3c24xx_nand_driver = {
.id_table = s3c24xx_driver_ids,
.driver = {
.name = "s3c24xx-nand",
+ .of_match_table = s3c24xx_nand_dt_ids,
},
};
diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c
index 888fd314c62a..72369bd079af 100644
--- a/drivers/mtd/nand/socrates_nand.c
+++ b/drivers/mtd/nand/socrates_nand.c
@@ -187,17 +187,9 @@ static int socrates_nand_probe(struct platform_device *ofdev)
dev_set_drvdata(&ofdev->dev, host);
- /* first scan to find the device and get the page size */
- if (nand_scan_ident(mtd, 1, NULL)) {
- res = -ENXIO;
+ res = nand_scan(mtd, 1);
+ if (res)
goto out;
- }
-
- /* second phase scan */
- if (nand_scan_tail(mtd)) {
- res = -ENXIO;
- goto out;
- }
res = mtd_device_register(mtd, NULL, 0);
if (!res)
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 8b8470c4e6d0..e40482a65de6 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -145,6 +145,7 @@
#define NFC_ECC_PIPELINE BIT(3)
#define NFC_ECC_EXCEPTION BIT(4)
#define NFC_ECC_BLOCK_SIZE_MSK BIT(5)
+#define NFC_ECC_BLOCK_512 BIT(5)
#define NFC_RANDOM_EN BIT(9)
#define NFC_RANDOM_DIRECTION BIT(10)
#define NFC_ECC_MODE_MSK GENMASK(15, 12)
@@ -817,6 +818,9 @@ static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION |
NFC_ECC_PIPELINE;
+ if (nand->ecc.size == 512)
+ ecc_ctl |= NFC_ECC_BLOCK_512;
+
writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL);
}
diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c
new file mode 100644
index 000000000000..28c7f474be77
--- /dev/null
+++ b/drivers/mtd/nand/tango_nand.c
@@ -0,0 +1,676 @@
+/*
+ * Copyright (C) 2016 Sigma Designs
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+/* Offsets relative to chip->base */
+#define PBUS_CMD 0
+#define PBUS_ADDR 4
+#define PBUS_DATA 8
+
+/* Offsets relative to reg_base */
+#define NFC_STATUS 0x00
+#define NFC_FLASH_CMD 0x04
+#define NFC_DEVICE_CFG 0x08
+#define NFC_TIMING1 0x0c
+#define NFC_TIMING2 0x10
+#define NFC_XFER_CFG 0x14
+#define NFC_PKT_0_CFG 0x18
+#define NFC_PKT_N_CFG 0x1c
+#define NFC_BB_CFG 0x20
+#define NFC_ADDR_PAGE 0x24
+#define NFC_ADDR_OFFSET 0x28
+#define NFC_XFER_STATUS 0x2c
+
+/* NFC_STATUS values */
+#define CMD_READY BIT(31)
+
+/* NFC_FLASH_CMD values */
+#define NFC_READ 1
+#define NFC_WRITE 2
+
+/* NFC_XFER_STATUS values */
+#define PAGE_IS_EMPTY BIT(16)
+
+/* Offsets relative to mem_base */
+#define METADATA 0x000
+#define ERROR_REPORT 0x1c0
+
+/*
+ * Error reports are split in two bytes:
+ * byte 0 for the first packet in the page (PKT_0)
+ * byte 1 for other packets in the page (PKT_N, for N > 0)
+ * ERR_COUNT_PKT_N is the max error count over all but the first packet.
+ */
+#define DECODE_OK_PKT_0(v) ((v) & BIT(7))
+#define DECODE_OK_PKT_N(v) ((v) & BIT(15))
+#define ERR_COUNT_PKT_0(v) (((v) >> 0) & 0x3f)
+#define ERR_COUNT_PKT_N(v) (((v) >> 8) & 0x3f)
+
+/* Offsets relative to pbus_base */
+#define PBUS_CS_CTRL 0x83c
+#define PBUS_PAD_MODE 0x8f0
+
+/* PBUS_CS_CTRL values */
+#define PBUS_IORDY BIT(31)
+
+/*
+ * PBUS_PAD_MODE values
+ * In raw mode, the driver communicates directly with the NAND chips.
+ * In NFC mode, the NAND Flash controller manages the communication.
+ * We use NFC mode for read and write; raw mode for everything else.
+ */
+#define MODE_RAW 0
+#define MODE_NFC BIT(31)
+
+#define METADATA_SIZE 4
+#define BBM_SIZE 6
+#define FIELD_ORDER 15
+
+#define MAX_CS 4
+
+struct tango_nfc {
+ struct nand_hw_control hw;
+ void __iomem *reg_base;
+ void __iomem *mem_base;
+ void __iomem *pbus_base;
+ struct tango_chip *chips[MAX_CS];
+ struct dma_chan *chan;
+ int freq_kHz;
+};
+
+#define to_tango_nfc(ptr) container_of(ptr, struct tango_nfc, hw)
+
+struct tango_chip {
+ struct nand_chip nand_chip;
+ void __iomem *base;
+ u32 timing1;
+ u32 timing2;
+ u32 xfer_cfg;
+ u32 pkt_0_cfg;
+ u32 pkt_n_cfg;
+ u32 bb_cfg;
+};
+
+#define to_tango_chip(ptr) container_of(ptr, struct tango_chip, nand_chip)
+
+#define XFER_CFG(cs, page_count, steps, metadata_size) \
+ ((cs) << 24 | (page_count) << 16 | (steps) << 8 | (metadata_size))
+
+#define PKT_CFG(size, strength) ((size) << 16 | (strength))
+
+#define BB_CFG(bb_offset, bb_size) ((bb_offset) << 16 | (bb_size))
+
+#define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3))
+
+static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+{
+ struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+ if (ctrl & NAND_CLE)
+ writeb_relaxed(dat, tchip->base + PBUS_CMD);
+
+ if (ctrl & NAND_ALE)
+ writeb_relaxed(dat, tchip->base + PBUS_ADDR);
+}
+
+static int tango_dev_ready(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+
+ return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY;
+}
+
+static u8 tango_read_byte(struct mtd_info *mtd)
+{
+ struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+ return readb_relaxed(tchip->base + PBUS_DATA);
+}
+
+static void tango_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+ struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+ ioread8_rep(tchip->base + PBUS_DATA, buf, len);
+}
+
+static void tango_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+ struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+ iowrite8_rep(tchip->base + PBUS_DATA, buf, len);
+}
+
+static void tango_select_chip(struct mtd_info *mtd, int idx)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+ struct tango_chip *tchip = to_tango_chip(chip);
+
+ if (idx < 0)
+ return; /* No "chip unselect" function */
+
+ writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1);
+ writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2);
+ writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG);
+ writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG);
+ writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG);
+ writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG);
+}
+
+/*
+ * The controller does not check for bitflips in erased pages,
+ * therefore software must check instead.
+ */
+static int check_erased_page(struct nand_chip *chip, u8 *buf)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ u8 *meta = chip->oob_poi + BBM_SIZE;
+ u8 *ecc = chip->oob_poi + BBM_SIZE + METADATA_SIZE;
+ const int ecc_size = chip->ecc.bytes;
+ const int pkt_size = chip->ecc.size;
+ int i, res, meta_len, bitflips = 0;
+
+ for (i = 0; i < chip->ecc.steps; ++i) {
+ meta_len = i ? 0 : METADATA_SIZE;
+ res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
+ meta, meta_len,
+ chip->ecc.strength);
+ if (res < 0)
+ mtd->ecc_stats.failed++;
+
+ bitflips = max(res, bitflips);
+ buf += pkt_size;
+ ecc += ecc_size;
+ }
+
+ return bitflips;
+}
+
+static int decode_error_report(struct tango_nfc *nfc)
+{
+ u32 status, res;
+
+ status = readl_relaxed(nfc->reg_base + NFC_XFER_STATUS);
+ if (status & PAGE_IS_EMPTY)
+ return 0;
+
+ res = readl_relaxed(nfc->mem_base + ERROR_REPORT);
+
+ if (DECODE_OK_PKT_0(res) && DECODE_OK_PKT_N(res))
+ return max(ERR_COUNT_PKT_0(res), ERR_COUNT_PKT_N(res));
+
+ return -EBADMSG;
+}
+
+static void tango_dma_callback(void *arg)
+{
+ complete(arg);
+}
+
+static int do_dma(struct tango_nfc *nfc, int dir, int cmd, const void *buf,
+ int len, int page)
+{
+ void __iomem *addr = nfc->reg_base + NFC_STATUS;
+ struct dma_chan *chan = nfc->chan;
+ struct dma_async_tx_descriptor *desc;
+ struct scatterlist sg;
+ struct completion tx_done;
+ int err = -EIO;
+ u32 res, val;
+
+ sg_init_one(&sg, buf, len);
+ if (dma_map_sg(chan->device->dev, &sg, 1, dir) != 1)
+ return -EIO;
+
+ desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir, DMA_PREP_INTERRUPT);
+ if (!desc)
+ goto dma_unmap;
+
+ desc->callback = tango_dma_callback;
+ desc->callback_param = &tx_done;
+ init_completion(&tx_done);
+
+ writel_relaxed(MODE_NFC, nfc->pbus_base + PBUS_PAD_MODE);
+
+ writel_relaxed(page, nfc->reg_base + NFC_ADDR_PAGE);
+ writel_relaxed(0, nfc->reg_base + NFC_ADDR_OFFSET);
+ writel_relaxed(cmd, nfc->reg_base + NFC_FLASH_CMD);
+
+ dmaengine_submit(desc);
+ dma_async_issue_pending(chan);
+
+ res = wait_for_completion_timeout(&tx_done, HZ);
+ if (res > 0)
+ err = readl_poll_timeout(addr, val, val & CMD_READY, 0, 1000);
+
+ writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE);
+
+dma_unmap:
+ dma_unmap_sg(chan->device->dev, &sg, 1, dir);
+
+ return err;
+}
+
+static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+ u8 *buf, int oob_required, int page)
+{
+ struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+ int err, res, len = mtd->writesize;
+
+ if (oob_required)
+ chip->ecc.read_oob(mtd, chip, page);
+
+ err = do_dma(nfc, DMA_FROM_DEVICE, NFC_READ, buf, len, page);
+ if (err)
+ return err;
+
+ res = decode_error_report(nfc);
+ if (res < 0) {
+ chip->ecc.read_oob_raw(mtd, chip, page);
+ res = check_erased_page(chip, buf);
+ }
+
+ return res;
+}
+
+static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+ const u8 *buf, int oob_required, int page)
+{
+ struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+ int err, len = mtd->writesize;
+
+ /* Calling tango_write_oob() would send PAGEPROG twice */
+ if (oob_required)
+ return -ENOTSUPP;
+
+ writel_relaxed(0xffffffff, nfc->mem_base + METADATA);
+ err = do_dma(nfc, DMA_TO_DEVICE, NFC_WRITE, buf, len, page);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
+ *pos += len;
+
+ if (!*buf) {
+ /* skip over "len" bytes */
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, *pos, -1);
+ } else {
+ tango_read_buf(mtd, *buf, len);
+ *buf += len;
+ }
+}
+
+static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
+ *pos += len;
+
+ if (!*buf) {
+ /* skip over "len" bytes */
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, *pos, -1);
+ } else {
+ tango_write_buf(mtd, *buf, len);
+ *buf += len;
+ }
+}
+
+/*
+ * Physical page layout (not drawn to scale)
+ *
+ * NB: Bad Block Marker area splits PKT_N in two (N1, N2).
+ *
+ * +---+-----------------+-------+-----+-----------+-----+----+-------+
+ * | M | PKT_0 | ECC_0 | ... | N1 | BBM | N2 | ECC_N |
+ * +---+-----------------+-------+-----+-----------+-----+----+-------+
+ *
+ * Logical page layout:
+ *
+ * +-----+---+-------+-----+-------+
+ * oob = | BBM | M | ECC_0 | ... | ECC_N |
+ * +-----+---+-------+-----+-------+
+ *
+ * +-----------------+-----+-----------------+
+ * buf = | PKT_0 | ... | PKT_N |
+ * +-----------------+-----+-----------------+
+ */
+static void raw_read(struct nand_chip *chip, u8 *buf, u8 *oob)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ u8 *oob_orig = oob;
+ const int page_size = mtd->writesize;
+ const int ecc_size = chip->ecc.bytes;
+ const int pkt_size = chip->ecc.size;
+ int pos = 0; /* position within physical page */
+ int rem = page_size; /* bytes remaining until BBM area */
+
+ if (oob)
+ oob += BBM_SIZE;
+
+ aux_read(chip, &oob, METADATA_SIZE, &pos);
+
+ while (rem > pkt_size) {
+ aux_read(chip, &buf, pkt_size, &pos);
+ aux_read(chip, &oob, ecc_size, &pos);
+ rem = page_size - pos;
+ }
+
+ aux_read(chip, &buf, rem, &pos);
+ aux_read(chip, &oob_orig, BBM_SIZE, &pos);
+ aux_read(chip, &buf, pkt_size - rem, &pos);
+ aux_read(chip, &oob, ecc_size, &pos);
+}
+
+static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ const u8 *oob_orig = oob;
+ const int page_size = mtd->writesize;
+ const int ecc_size = chip->ecc.bytes;
+ const int pkt_size = chip->ecc.size;
+ int pos = 0; /* position within physical page */
+ int rem = page_size; /* bytes remaining until BBM area */
+
+ if (oob)
+ oob += BBM_SIZE;
+
+ aux_write(chip, &oob, METADATA_SIZE, &pos);
+
+ while (rem > pkt_size) {
+ aux_write(chip, &buf, pkt_size, &pos);
+ aux_write(chip, &oob, ecc_size, &pos);
+ rem = page_size - pos;
+ }
+
+ aux_write(chip, &buf, rem, &pos);
+ aux_write(chip, &oob_orig, BBM_SIZE, &pos);
+ aux_write(chip, &buf, pkt_size - rem, &pos);
+ aux_write(chip, &oob, ecc_size, &pos);
+}
+
+static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ u8 *buf, int oob_required, int page)
+{
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+ raw_read(chip, buf, chip->oob_poi);
+ return 0;
+}
+
+static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ const u8 *buf, int oob_required, int page)
+{
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
+ raw_write(chip, buf, chip->oob_poi);
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ return 0;
+}
+
+static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+ raw_read(chip, NULL, chip->oob_poi);
+ return 0;
+}
+
+static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
+ raw_write(chip, NULL, chip->oob_poi);
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ chip->waitfunc(mtd, chip);
+ return 0;
+}
+
+static int oob_ecc(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+ if (idx >= ecc->steps)
+ return -ERANGE;
+
+ res->offset = BBM_SIZE + METADATA_SIZE + ecc->bytes * idx;
+ res->length = ecc->bytes;
+
+ return 0;
+}
+
+static int oob_free(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
+{
+ return -ERANGE; /* no free space in spare area */
+}
+
+static const struct mtd_ooblayout_ops tango_nand_ooblayout_ops = {
+ .ecc = oob_ecc,
+ .free = oob_free,
+};
+
+static u32 to_ticks(int kHz, int ps)
+{
+ return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC);
+}
+
+static int tango_set_timings(struct mtd_info *mtd,
+ const struct nand_data_interface *conf,
+ bool check_only)
+{
+ const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+ struct tango_chip *tchip = to_tango_chip(chip);
+ u32 Trdy, Textw, Twc, Twpw, Tacc, Thold, Trpw, Textr;
+ int kHz = nfc->freq_kHz;
+
+ if (IS_ERR(sdr))
+ return PTR_ERR(sdr);
+
+ if (check_only)
+ return 0;
+
+ Trdy = to_ticks(kHz, sdr->tCEA_max - sdr->tREA_max);
+ Textw = to_ticks(kHz, sdr->tWB_max);
+ Twc = to_ticks(kHz, sdr->tWC_min);
+ Twpw = to_ticks(kHz, sdr->tWC_min - sdr->tWP_min);
+
+ Tacc = to_ticks(kHz, sdr->tREA_max);
+ Thold = to_ticks(kHz, sdr->tREH_min);
+ Trpw = to_ticks(kHz, sdr->tRC_min - sdr->tREH_min);
+ Textr = to_ticks(kHz, sdr->tRHZ_max);
+
+ tchip->timing1 = TIMING(Trdy, Textw, Twc, Twpw);
+ tchip->timing2 = TIMING(Tacc, Thold, Trpw, Textr);
+
+ return 0;
+}
+
+static int chip_init(struct device *dev, struct device_node *np)
+{
+ u32 cs;
+ int err, res;
+ struct mtd_info *mtd;
+ struct nand_chip *chip;
+ struct tango_chip *tchip;
+ struct nand_ecc_ctrl *ecc;
+ struct tango_nfc *nfc = dev_get_drvdata(dev);
+
+ tchip = devm_kzalloc(dev, sizeof(*tchip), GFP_KERNEL);
+ if (!tchip)
+ return -ENOMEM;
+
+ res = of_property_count_u32_elems(np, "reg");
+ if (res < 0)
+ return res;
+
+ if (res != 1)
+ return -ENOTSUPP; /* Multi-CS chips are not supported */
+
+ err = of_property_read_u32_index(np, "reg", 0, &cs);
+ if (err)
+ return err;
+
+ if (cs >= MAX_CS)
+ return -EINVAL;
+
+ chip = &tchip->nand_chip;
+ ecc = &chip->ecc;
+ mtd = nand_to_mtd(chip);
+
+ chip->read_byte = tango_read_byte;
+ chip->write_buf = tango_write_buf;
+ chip->read_buf = tango_read_buf;
+ chip->select_chip = tango_select_chip;
+ chip->cmd_ctrl = tango_cmd_ctrl;
+ chip->dev_ready = tango_dev_ready;
+ chip->setup_data_interface = tango_set_timings;
+ chip->options = NAND_USE_BOUNCE_BUFFER |
+ NAND_NO_SUBPAGE_WRITE |
+ NAND_WAIT_TCCS;
+ chip->controller = &nfc->hw;
+ tchip->base = nfc->pbus_base + (cs * 256);
+
+ nand_set_flash_node(chip, np);
+ mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
+ mtd->dev.parent = dev;
+
+ err = nand_scan_ident(mtd, 1, NULL);
+ if (err)
+ return err;
+
+ ecc->mode = NAND_ECC_HW;
+ ecc->algo = NAND_ECC_BCH;
+ ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE);
+
+ ecc->read_page_raw = tango_read_page_raw;
+ ecc->write_page_raw = tango_write_page_raw;
+ ecc->read_page = tango_read_page;
+ ecc->write_page = tango_write_page;
+ ecc->read_oob = tango_read_oob;
+ ecc->write_oob = tango_write_oob;
+ ecc->options = NAND_ECC_CUSTOM_PAGE_ACCESS;
+
+ err = nand_scan_tail(mtd);
+ if (err)
+ return err;
+
+ tchip->xfer_cfg = XFER_CFG(cs, 1, ecc->steps, METADATA_SIZE);
+ tchip->pkt_0_cfg = PKT_CFG(ecc->size + METADATA_SIZE, ecc->strength);
+ tchip->pkt_n_cfg = PKT_CFG(ecc->size, ecc->strength);
+ tchip->bb_cfg = BB_CFG(mtd->writesize, BBM_SIZE);
+
+ err = mtd_device_register(mtd, NULL, 0);
+ if (err)
+ return err;
+
+ nfc->chips[cs] = tchip;
+
+ return 0;
+}
+
+static int tango_nand_remove(struct platform_device *pdev)
+{
+ int cs;
+ struct tango_nfc *nfc = platform_get_drvdata(pdev);
+
+ dma_release_channel(nfc->chan);
+
+ for (cs = 0; cs < MAX_CS; ++cs) {
+ if (nfc->chips[cs])
+ nand_release(nand_to_mtd(&nfc->chips[cs]->nand_chip));
+ }
+
+ return 0;
+}
+
+static int tango_nand_probe(struct platform_device *pdev)
+{
+ int err;
+ struct clk *clk;
+ struct resource *res;
+ struct tango_nfc *nfc;
+ struct device_node *np;
+
+ nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
+ if (!nfc)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ nfc->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(nfc->reg_base))
+ return PTR_ERR(nfc->reg_base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ nfc->mem_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(nfc->mem_base))
+ return PTR_ERR(nfc->mem_base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ nfc->pbus_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(nfc->pbus_base))
+ return PTR_ERR(nfc->pbus_base);
+
+ clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ nfc->chan = dma_request_chan(&pdev->dev, "nfc_sbox");
+ if (IS_ERR(nfc->chan))
+ return PTR_ERR(nfc->chan);
+
+ platform_set_drvdata(pdev, nfc);
+ nand_hw_control_init(&nfc->hw);
+ nfc->freq_kHz = clk_get_rate(clk) / 1000;
+
+ for_each_child_of_node(pdev->dev.of_node, np) {
+ err = chip_init(&pdev->dev, np);
+ if (err) {
+ tango_nand_remove(pdev);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static const struct of_device_id tango_nand_ids[] = {
+ { .compatible = "sigma,smp8758-nand" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver tango_nand_driver = {
+ .probe = tango_nand_probe,
+ .remove = tango_nand_remove,
+ .driver = {
+ .name = "tango-nand",
+ .of_match_table = tango_nand_ids,
+ },
+};
+
+module_platform_driver(tango_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sigma Designs");
+MODULE_DESCRIPTION("Tango4 NAND Flash controller driver");
diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c
index 08b30549ec0a..fc5e773f8b60 100644
--- a/drivers/mtd/nand/tmio_nand.c
+++ b/drivers/mtd/nand/tmio_nand.c
@@ -435,10 +435,10 @@ static int tmio_probe(struct platform_device *dev)
nand_chip->waitfunc = tmio_nand_wait;
/* Scan to find existence of the device */
- if (nand_scan(mtd, 1)) {
- retval = -ENODEV;
+ retval = nand_scan(mtd, 1);
+ if (retval)
goto err_irq;
- }
+
/* Register the partitions */
retval = mtd_device_parse_register(mtd, NULL, NULL,
data ? data->partition : NULL,
diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
index 3ad514c44dcb..3ea4bb19e12d 100644
--- a/drivers/mtd/nand/vf610_nfc.c
+++ b/drivers/mtd/nand/vf610_nfc.c
@@ -717,10 +717,9 @@ static int vf610_nfc_probe(struct platform_device *pdev)
vf610_nfc_preinit_controller(nfc);
/* first scan to find the device and get the page size */
- if (nand_scan_ident(mtd, 1, NULL)) {
- err = -ENXIO;
+ err = nand_scan_ident(mtd, 1, NULL);
+ if (err)
goto error;
- }
vf610_nfc_init_controller(nfc);
@@ -775,10 +774,9 @@ static int vf610_nfc_probe(struct platform_device *pdev)
}
/* second phase scan */
- if (nand_scan_tail(mtd)) {
- err = -ENXIO;
+ err = nand_scan_tail(mtd);
+ if (err)
goto error;
- }
platform_set_drvdata(pdev, mtd);
diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
index d403ba7b8f43..d489fbd07c12 100644
--- a/drivers/mtd/spi-nor/cadence-quadspi.c
+++ b/drivers/mtd/spi-nor/cadence-quadspi.c
@@ -1077,12 +1077,14 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
/* Get flash device data */
for_each_available_child_of_node(dev->of_node, np) {
- if (of_property_read_u32(np, "reg", &cs)) {
+ ret = of_property_read_u32(np, "reg", &cs);
+ if (ret) {
dev_err(dev, "Couldn't determine chip select.\n");
goto err;
}
- if (cs > CQSPI_MAX_CHIPSELECT) {
+ if (cs >= CQSPI_MAX_CHIPSELECT) {
+ ret = -EINVAL;
dev_err(dev, "Chip select %d out of range.\n", cs);
goto err;
}
diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
index 5c82e4ef1904..b4d8953fb30a 100644
--- a/drivers/mtd/spi-nor/fsl-quadspi.c
+++ b/drivers/mtd/spi-nor/fsl-quadspi.c
@@ -224,7 +224,7 @@ struct fsl_qspi_devtype_data {
int driver_data;
};
-static struct fsl_qspi_devtype_data vybrid_data = {
+static const struct fsl_qspi_devtype_data vybrid_data = {
.devtype = FSL_QUADSPI_VYBRID,
.rxfifo = 128,
.txfifo = 64,
@@ -232,7 +232,7 @@ static struct fsl_qspi_devtype_data vybrid_data = {
.driver_data = QUADSPI_QUIRK_SWAP_ENDIAN,
};
-static struct fsl_qspi_devtype_data imx6sx_data = {
+static const struct fsl_qspi_devtype_data imx6sx_data = {
.devtype = FSL_QUADSPI_IMX6SX,
.rxfifo = 128,
.txfifo = 512,
@@ -241,7 +241,7 @@ static struct fsl_qspi_devtype_data imx6sx_data = {
| QUADSPI_QUIRK_TKT245618,
};
-static struct fsl_qspi_devtype_data imx7d_data = {
+static const struct fsl_qspi_devtype_data imx7d_data = {
.devtype = FSL_QUADSPI_IMX7D,
.rxfifo = 512,
.txfifo = 512,
@@ -250,7 +250,7 @@ static struct fsl_qspi_devtype_data imx7d_data = {
| QUADSPI_QUIRK_4X_INT_CLK,
};
-static struct fsl_qspi_devtype_data imx6ul_data = {
+static const struct fsl_qspi_devtype_data imx6ul_data = {
.devtype = FSL_QUADSPI_IMX6UL,
.rxfifo = 128,
.txfifo = 512,
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index d0fc165d7d66..da7cd69d4857 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -799,6 +799,7 @@ static const struct flash_info spi_nor_ids[] = {
{ "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) },
{ "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, SECT_4K) },
+ { "at25df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
{ "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) },
{ "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) },
@@ -825,6 +826,7 @@ static const struct flash_info spi_nor_ids[] = {
/* Everspin */
{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
{ "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+ { "mr25h40", CAT25_INFO(512 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
/* Fujitsu */
{ "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) },
@@ -872,11 +874,13 @@ static const struct flash_info spi_nor_ids[] = {
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
+ { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K) },
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
{ "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
/* Micron */
+ { "n25q016a", INFO(0x20bb15, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) },
{ "n25q032a", INFO(0x20bb16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) },
{ "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) },
@@ -905,7 +909,7 @@ static const struct flash_info spi_nor_ids[] = {
{ "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) },
{ "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) },
- { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
+ { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) },
@@ -921,6 +925,7 @@ static const struct flash_info spi_nor_ids[] = {
{ "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) },
{ "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) },
{ "s25fl204k", INFO(0x014013, 0, 64 * 1024, 8, SECT_4K | SPI_NOR_DUAL_READ) },
+ { "s25fl208k", INFO(0x014014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ) },
/* SST -- large erase sizes are "overlays", "sectors" are 4K */
{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) },
@@ -1255,6 +1260,13 @@ static int spansion_quad_enable(struct spi_nor *nor)
return -EINVAL;
}
+ ret = spi_nor_wait_till_ready(nor);
+ if (ret) {
+ dev_err(nor->dev,
+ "timeout while writing configuration register\n");
+ return ret;
+ }
+
/* read back and check it */
ret = read_cr(nor);
if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 4da379f28d5d..f7222dc6581d 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1775,6 +1775,9 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
continue;
+ if (!ds->ports[port].netdev)
+ continue;
+
if (vlan.data[i] ==
GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
continue;
@@ -1783,6 +1786,9 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
chip->ports[port].bridge_dev)
break; /* same bridge, check next VLAN */
+ if (!chip->ports[i].bridge_dev)
+ continue;
+
netdev_warn(ds->ports[port].netdev,
"hardware VLAN %d already used by %s\n",
vlan.vid,
diff --git a/drivers/net/ethernet/3com/3c515.c b/drivers/net/ethernet/3com/3c515.c
index b9f4c463e516..be5b80103bec 100644
--- a/drivers/net/ethernet/3com/3c515.c
+++ b/drivers/net/ethernet/3com/3c515.c
@@ -627,6 +627,8 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr,
spin_lock_init(&vp->lock);
+ setup_timer(&vp->timer, corkscrew_timer, (unsigned long) dev);
+
/* Read the station address from the EEPROM. */
EL3WINDOW(0);
for (i = 0; i < 0x18; i++) {
@@ -707,6 +709,7 @@ static int corkscrew_open(struct net_device *dev)
{
int ioaddr = dev->base_addr;
struct corkscrew_private *vp = netdev_priv(dev);
+ bool armtimer = false;
__u32 config;
int i;
@@ -731,12 +734,7 @@ static int corkscrew_open(struct net_device *dev)
if (corkscrew_debug > 1)
pr_debug("%s: Initial media type %s.\n",
dev->name, media_tbl[dev->if_port].name);
-
- init_timer(&vp->timer);
- vp->timer.expires = jiffies + media_tbl[dev->if_port].wait;
- vp->timer.data = (unsigned long) dev;
- vp->timer.function = corkscrew_timer; /* timer handler */
- add_timer(&vp->timer);
+ armtimer = true;
} else
dev->if_port = vp->default_media;
@@ -776,6 +774,9 @@ static int corkscrew_open(struct net_device *dev)
return -EAGAIN;
}
+ if (armtimer)
+ mod_timer(&vp->timer, jiffies + media_tbl[dev->if_port].wait);
+
if (corkscrew_debug > 1) {
EL3WINDOW(4);
pr_debug("%s: corkscrew_open() irq %d media status %4.4x.\n",
@@ -1426,7 +1427,7 @@ static int corkscrew_close(struct net_device *dev)
dev->name, rx_nocopy, rx_copy, queued_packet);
}
- del_timer(&vp->timer);
+ del_timer_sync(&vp->timer);
/* Turn off statistics ASAP. We update lp->stats below. */
outw(StatsDisable, ioaddr + EL3_CMD);
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 6e16e441f85e..e4c28fed61d5 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -166,7 +166,6 @@ source "drivers/net/ethernet/seeq/Kconfig"
source "drivers/net/ethernet/silan/Kconfig"
source "drivers/net/ethernet/sis/Kconfig"
source "drivers/net/ethernet/sfc/Kconfig"
-source "drivers/net/ethernet/sfc/falcon/Kconfig"
source "drivers/net/ethernet/sgi/Kconfig"
source "drivers/net/ethernet/smsc/Kconfig"
source "drivers/net/ethernet/stmicro/Kconfig"
diff --git a/drivers/net/ethernet/brocade/bna/bna_enet.c b/drivers/net/ethernet/brocade/bna/bna_enet.c
index 4e5c3874a50f..bba81735ce87 100644
--- a/drivers/net/ethernet/brocade/bna/bna_enet.c
+++ b/drivers/net/ethernet/brocade/bna/bna_enet.c
@@ -1676,10 +1676,10 @@ bna_cb_ioceth_reset(void *arg)
}
static struct bfa_ioc_cbfn bna_ioceth_cbfn = {
- bna_cb_ioceth_enable,
- bna_cb_ioceth_disable,
- bna_cb_ioceth_hbfail,
- bna_cb_ioceth_reset
+ .enable_cbfn = bna_cb_ioceth_enable,
+ .disable_cbfn = bna_cb_ioceth_disable,
+ .hbfail_cbfn = bna_cb_ioceth_hbfail,
+ .reset_cbfn = bna_cb_ioceth_reset
};
static void bna_attr_init(struct bna_ioceth *ioceth)
diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig
index f0bcb15d3fec..608bea171956 100644
--- a/drivers/net/ethernet/cadence/Kconfig
+++ b/drivers/net/ethernet/cadence/Kconfig
@@ -31,4 +31,13 @@ config MACB
To compile this driver as a module, choose M here: the module
will be called macb.
+config MACB_PCI
+ tristate "Cadence PCI MACB/GEM support"
+ depends on MACB && PCI && COMMON_CLK
+ ---help---
+ This is PCI wrapper for MACB driver.
+
+ To compile this driver as a module, choose M here: the module
+ will be called macb_pci.
+
endif # NET_CADENCE
diff --git a/drivers/net/ethernet/cadence/Makefile b/drivers/net/ethernet/cadence/Makefile
index 91f79b1f0505..4ba75594d5c5 100644
--- a/drivers/net/ethernet/cadence/Makefile
+++ b/drivers/net/ethernet/cadence/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_MACB) += macb.o
+obj-$(CONFIG_MACB_PCI) += macb_pci.o
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index 538544a7c642..c0fb80acc2da 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -404,6 +404,8 @@ static int macb_mii_probe(struct net_device *dev)
phy_irq = gpio_to_irq(pdata->phy_irq_pin);
phydev->irq = (phy_irq < 0) ? PHY_POLL : phy_irq;
}
+ } else {
+ phydev->irq = PHY_POLL;
}
/* attach the mac to the phy */
@@ -482,6 +484,9 @@ static int macb_mii_init(struct macb *bp)
goto err_out_unregister_bus;
}
} else {
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ bp->mii_bus->irq[i] = PHY_POLL;
+
if (pdata)
bp->mii_bus->phy_mask = pdata->phy_mask;
@@ -2523,16 +2528,24 @@ static int macb_clk_init(struct platform_device *pdev, struct clk **pclk,
struct clk **hclk, struct clk **tx_clk,
struct clk **rx_clk)
{
+ struct macb_platform_data *pdata;
int err;
- *pclk = devm_clk_get(&pdev->dev, "pclk");
+ pdata = dev_get_platdata(&pdev->dev);
+ if (pdata) {
+ *pclk = pdata->pclk;
+ *hclk = pdata->hclk;
+ } else {
+ *pclk = devm_clk_get(&pdev->dev, "pclk");
+ *hclk = devm_clk_get(&pdev->dev, "hclk");
+ }
+
if (IS_ERR(*pclk)) {
err = PTR_ERR(*pclk);
dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", err);
return err;
}
- *hclk = devm_clk_get(&pdev->dev, "hclk");
if (IS_ERR(*hclk)) {
err = PTR_ERR(*hclk);
dev_err(&pdev->dev, "failed to get hclk (%u)\n", err);
@@ -3107,15 +3120,23 @@ static const struct of_device_id macb_dt_ids[] = {
MODULE_DEVICE_TABLE(of, macb_dt_ids);
#endif /* CONFIG_OF */
+static const struct macb_config default_gem_config = {
+ .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO,
+ .dma_burst_length = 16,
+ .clk_init = macb_clk_init,
+ .init = macb_init,
+ .jumbo_max_len = 10240,
+};
+
static int macb_probe(struct platform_device *pdev)
{
+ const struct macb_config *macb_config = &default_gem_config;
int (*clk_init)(struct platform_device *, struct clk **,
struct clk **, struct clk **, struct clk **)
- = macb_clk_init;
- int (*init)(struct platform_device *) = macb_init;
+ = macb_config->clk_init;
+ int (*init)(struct platform_device *) = macb_config->init;
struct device_node *np = pdev->dev.of_node;
struct device_node *phy_node;
- const struct macb_config *macb_config = NULL;
struct clk *pclk, *hclk = NULL, *tx_clk = NULL, *rx_clk = NULL;
unsigned int queue_mask, num_queues;
struct macb_platform_data *pdata;
diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
new file mode 100644
index 000000000000..92be2cd8f817
--- /dev/null
+++ b/drivers/net/ethernet/cadence/macb_pci.c
@@ -0,0 +1,153 @@
+/**
+ * macb_pci.c - Cadence GEM PCI wrapper.
+ *
+ * Copyright (C) 2016 Cadence Design Systems - http://www.cadence.com
+ *
+ * Authors: Rafal Ozieblo <rafalo@cadence.com>
+ * Bartosz Folta <bfolta@cadence.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License 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/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_data/macb.h>
+#include <linux/platform_device.h>
+#include "macb.h"
+
+#define PCI_DRIVER_NAME "macb_pci"
+#define PLAT_DRIVER_NAME "macb"
+
+#define CDNS_VENDOR_ID 0x17cd
+#define CDNS_DEVICE_ID 0xe007
+
+#define GEM_PCLK_RATE 50000000
+#define GEM_HCLK_RATE 50000000
+
+static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ int err;
+ struct platform_device *plat_dev;
+ struct platform_device_info plat_info;
+ struct macb_platform_data plat_data;
+ struct resource res[2];
+
+ /* sanity check */
+ if (!id)
+ return -EINVAL;
+
+ /* enable pci device */
+ err = pci_enable_device(pdev);
+ if (err < 0) {
+ dev_err(&pdev->dev, "Enabling PCI device has failed: 0x%04X",
+ err);
+ return -EACCES;
+ }
+
+ pci_set_master(pdev);
+
+ /* set up resources */
+ memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
+ res[0].start = pdev->resource[0].start;
+ res[0].end = pdev->resource[0].end;
+ res[0].name = PCI_DRIVER_NAME;
+ res[0].flags = IORESOURCE_MEM;
+ res[1].start = pdev->irq;
+ res[1].name = PCI_DRIVER_NAME;
+ res[1].flags = IORESOURCE_IRQ;
+
+ dev_info(&pdev->dev, "EMAC physical base addr = 0x%p\n",
+ (void *)(uintptr_t)pci_resource_start(pdev, 0));
+
+ /* set up macb platform data */
+ memset(&plat_data, 0, sizeof(plat_data));
+
+ /* initialize clocks */
+ plat_data.pclk = clk_register_fixed_rate(&pdev->dev, "pclk", NULL, 0,
+ GEM_PCLK_RATE);
+ if (IS_ERR(plat_data.pclk)) {
+ err = PTR_ERR(plat_data.pclk);
+ goto err_pclk_register;
+ }
+
+ plat_data.hclk = clk_register_fixed_rate(&pdev->dev, "hclk", NULL, 0,
+ GEM_HCLK_RATE);
+ if (IS_ERR(plat_data.hclk)) {
+ err = PTR_ERR(plat_data.hclk);
+ goto err_hclk_register;
+ }
+
+ /* set up platform device info */
+ memset(&plat_info, 0, sizeof(plat_info));
+ plat_info.parent = &pdev->dev;
+ plat_info.fwnode = pdev->dev.fwnode;
+ plat_info.name = PLAT_DRIVER_NAME;
+ plat_info.id = pdev->devfn;
+ plat_info.res = res;
+ plat_info.num_res = ARRAY_SIZE(res);
+ plat_info.data = &plat_data;
+ plat_info.size_data = sizeof(plat_data);
+ plat_info.dma_mask = DMA_BIT_MASK(32);
+
+ /* register platform device */
+ plat_dev = platform_device_register_full(&plat_info);
+ if (IS_ERR(plat_dev)) {
+ err = PTR_ERR(plat_dev);
+ goto err_plat_dev_register;
+ }
+
+ pci_set_drvdata(pdev, plat_dev);
+
+ return 0;
+
+err_plat_dev_register:
+ clk_unregister(plat_data.hclk);
+
+err_hclk_register:
+ clk_unregister(plat_data.pclk);
+
+err_pclk_register:
+ pci_disable_device(pdev);
+ return err;
+}
+
+static void macb_remove(struct pci_dev *pdev)
+{
+ struct platform_device *plat_dev = pci_get_drvdata(pdev);
+ struct macb_platform_data *plat_data = dev_get_platdata(&plat_dev->dev);
+
+ platform_device_unregister(plat_dev);
+ pci_disable_device(pdev);
+ clk_unregister(plat_data->pclk);
+ clk_unregister(plat_data->hclk);
+}
+
+static struct pci_device_id dev_id_table[] = {
+ { PCI_DEVICE(CDNS_VENDOR_ID, CDNS_DEVICE_ID), },
+ { 0, }
+};
+
+static struct pci_driver macb_pci_driver = {
+ .name = PCI_DRIVER_NAME,
+ .id_table = dev_id_table,
+ .probe = macb_probe,
+ .remove = macb_remove,
+};
+
+module_pci_driver(macb_pci_driver);
+MODULE_DEVICE_TABLE(pci, dev_id_table);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cadence NIC PCI wrapper");
diff --git a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c
index 16e12c45904b..21f80f5744ba 100644
--- a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c
+++ b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c
@@ -1469,6 +1469,12 @@ static int octeon_mgmt_probe(struct platform_device *pdev)
p->agl = (u64)devm_ioremap(&pdev->dev, p->agl_phys, p->agl_size);
p->agl_prt_ctl = (u64)devm_ioremap(&pdev->dev, p->agl_prt_ctl_phys,
p->agl_prt_ctl_size);
+ if (!p->mix || !p->agl || !p->agl_prt_ctl) {
+ dev_err(&pdev->dev, "failed to map I/O memory\n");
+ result = -ENOMEM;
+ goto err;
+ }
+
spin_lock_init(&p->lock);
skb_queue_head_init(&p->tx_list);
diff --git a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
index 81d1d0bc7553..3a05f9098e75 100644
--- a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
+++ b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
@@ -568,28 +568,33 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
reg_block_dump(ap, buf, A_MC5_CONFIG, A_MC5_MASK_WRITE_CMD);
}
-static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int get_link_ksettings(struct net_device *dev,
+ struct ethtool_link_ksettings *cmd)
{
struct adapter *adapter = dev->ml_priv;
struct port_info *p = &adapter->port[dev->if_port];
+ u32 supported, advertising;
- cmd->supported = p->link_config.supported;
- cmd->advertising = p->link_config.advertising;
+ supported = p->link_config.supported;
+ advertising = p->link_config.advertising;
if (netif_carrier_ok(dev)) {
- ethtool_cmd_speed_set(cmd, p->link_config.speed);
- cmd->duplex = p->link_config.duplex;
+ cmd->base.speed = p->link_config.speed;
+ cmd->base.duplex = p->link_config.duplex;
} else {
- ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
- cmd->duplex = DUPLEX_UNKNOWN;
+ cmd->base.speed = SPEED_UNKNOWN;
+ cmd->base.duplex = DUPLEX_UNKNOWN;
}
- cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
- cmd->phy_address = p->phy->mdio.prtad;
- cmd->transceiver = XCVR_EXTERNAL;
- cmd->autoneg = p->link_config.autoneg;
- cmd->maxtxpkt = 0;
- cmd->maxrxpkt = 0;
+ cmd->base.port = (supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
+ cmd->base.phy_address = p->phy->mdio.prtad;
+ cmd->base.autoneg = p->link_config.autoneg;
+
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
+ supported);
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
+ advertising);
+
return 0;
}
@@ -628,36 +633,41 @@ static int speed_duplex_to_caps(int speed, int duplex)
ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \
ADVERTISED_10000baseT_Full)
-static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int set_link_ksettings(struct net_device *dev,
+ const struct ethtool_link_ksettings *cmd)
{
struct adapter *adapter = dev->ml_priv;
struct port_info *p = &adapter->port[dev->if_port];
struct link_config *lc = &p->link_config;
+ u32 advertising;
+
+ ethtool_convert_link_mode_to_legacy_u32(&advertising,
+ cmd->link_modes.advertising);
if (!(lc->supported & SUPPORTED_Autoneg))
return -EOPNOTSUPP; /* can't change speed/duplex */
- if (cmd->autoneg == AUTONEG_DISABLE) {
- u32 speed = ethtool_cmd_speed(cmd);
- int cap = speed_duplex_to_caps(speed, cmd->duplex);
+ if (cmd->base.autoneg == AUTONEG_DISABLE) {
+ u32 speed = cmd->base.speed;
+ int cap = speed_duplex_to_caps(speed, cmd->base.duplex);
if (!(lc->supported & cap) || (speed == SPEED_1000))
return -EINVAL;
lc->requested_speed = speed;
- lc->requested_duplex = cmd->duplex;
+ lc->requested_duplex = cmd->base.duplex;
lc->advertising = 0;
} else {
- cmd->advertising &= ADVERTISED_MASK;
- if (cmd->advertising & (cmd->advertising - 1))
- cmd->advertising = lc->supported;
- cmd->advertising &= lc->supported;
- if (!cmd->advertising)
+ advertising &= ADVERTISED_MASK;
+ if (advertising & (advertising - 1))
+ advertising = lc->supported;
+ advertising &= lc->supported;
+ if (!advertising)
return -EINVAL;
lc->requested_speed = SPEED_INVALID;
lc->requested_duplex = DUPLEX_INVALID;
- lc->advertising = cmd->advertising | ADVERTISED_Autoneg;
+ lc->advertising = advertising | ADVERTISED_Autoneg;
}
- lc->autoneg = cmd->autoneg;
+ lc->autoneg = cmd->base.autoneg;
if (netif_running(dev))
t1_link_start(p->phy, p->mac, lc);
return 0;
@@ -788,8 +798,6 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
}
static const struct ethtool_ops t1_ethtool_ops = {
- .get_settings = get_settings,
- .set_settings = set_settings,
.get_drvinfo = get_drvinfo,
.get_msglevel = get_msglevel,
.set_msglevel = set_msglevel,
@@ -807,6 +815,8 @@ static const struct ethtool_ops t1_ethtool_ops = {
.get_ethtool_stats = get_stats,
.get_regs_len = get_regs_len,
.get_regs = get_regs,
+ .get_link_ksettings = get_link_ksettings,
+ .set_link_ksettings = set_link_ksettings,
};
static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
index 092b3c16440b..7b2224ae72f2 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
@@ -1801,27 +1801,31 @@ static int set_phys_id(struct net_device *dev,
return 0;
}
-static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int get_link_ksettings(struct net_device *dev,
+ struct ethtool_link_ksettings *cmd)
{
struct port_info *p = netdev_priv(dev);
+ u32 supported;
- cmd->supported = p->link_config.supported;
- cmd->advertising = p->link_config.advertising;
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
+ p->link_config.supported);
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
+ p->link_config.advertising);
if (netif_carrier_ok(dev)) {
- ethtool_cmd_speed_set(cmd, p->link_config.speed);
- cmd->duplex = p->link_config.duplex;
+ cmd->base.speed = p->link_config.speed;
+ cmd->base.duplex = p->link_config.duplex;
} else {
- ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
- cmd->duplex = DUPLEX_UNKNOWN;
+ cmd->base.speed = SPEED_UNKNOWN;
+ cmd->base.duplex = DUPLEX_UNKNOWN;
}
- cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
- cmd->phy_address = p->phy.mdio.prtad;
- cmd->transceiver = XCVR_EXTERNAL;
- cmd->autoneg = p->link_config.autoneg;
- cmd->maxtxpkt = 0;
- cmd->maxrxpkt = 0;
+ ethtool_convert_link_mode_to_legacy_u32(&supported,
+ cmd->link_modes.supported);
+
+ cmd->base.port = (supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
+ cmd->base.phy_address = p->phy.mdio.prtad;
+ cmd->base.autoneg = p->link_config.autoneg;
return 0;
}
@@ -1860,44 +1864,49 @@ static int speed_duplex_to_caps(int speed, int duplex)
ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \
ADVERTISED_10000baseT_Full)
-static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int set_link_ksettings(struct net_device *dev,
+ const struct ethtool_link_ksettings *cmd)
{
struct port_info *p = netdev_priv(dev);
struct link_config *lc = &p->link_config;
+ u32 advertising;
+
+ ethtool_convert_link_mode_to_legacy_u32(&advertising,
+ cmd->link_modes.advertising);
if (!(lc->supported & SUPPORTED_Autoneg)) {
/*
* PHY offers a single speed/duplex. See if that's what's
* being requested.
*/
- if (cmd->autoneg == AUTONEG_DISABLE) {
- u32 speed = ethtool_cmd_speed(cmd);
- int cap = speed_duplex_to_caps(speed, cmd->duplex);
+ if (cmd->base.autoneg == AUTONEG_DISABLE) {
+ u32 speed = cmd->base.speed;
+ int cap = speed_duplex_to_caps(speed, cmd->base.duplex);
if (lc->supported & cap)
return 0;
}
return -EINVAL;
}
- if (cmd->autoneg == AUTONEG_DISABLE) {
- u32 speed = ethtool_cmd_speed(cmd);
- int cap = speed_duplex_to_caps(speed, cmd->duplex);
+ if (cmd->base.autoneg == AUTONEG_DISABLE) {
+ u32 speed = cmd->base.speed;
+ int cap = speed_duplex_to_caps(speed, cmd->base.duplex);
if (!(lc->supported & cap) || (speed == SPEED_1000))
return -EINVAL;
lc->requested_speed = speed;
- lc->requested_duplex = cmd->duplex;
+ lc->requested_duplex = cmd->base.duplex;
lc->advertising = 0;
} else {
- cmd->advertising &= ADVERTISED_MASK;
- cmd->advertising &= lc->supported;
- if (!cmd->advertising)
+ advertising &= ADVERTISED_MASK;
+ advertising &= lc->supported;
+ if (!advertising)
return -EINVAL;
lc->requested_speed = SPEED_INVALID;
lc->requested_duplex = DUPLEX_INVALID;
- lc->advertising = cmd->advertising | ADVERTISED_Autoneg;
+ lc->advertising = advertising | ADVERTISED_Autoneg;
}
- lc->autoneg = cmd->autoneg;
+ lc->autoneg = cmd->base.autoneg;
if (netif_running(dev))
t3_link_start(&p->phy, &p->mac, lc);
return 0;
@@ -2097,8 +2106,6 @@ static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
}
static const struct ethtool_ops cxgb_ethtool_ops = {
- .get_settings = get_settings,
- .set_settings = set_settings,
.get_drvinfo = get_drvinfo,
.get_msglevel = get_msglevel,
.set_msglevel = set_msglevel,
@@ -2120,6 +2127,8 @@ static const struct ethtool_ops cxgb_ethtool_ops = {
.get_regs_len = get_regs_len,
.get_regs = get_regs,
.get_wol = get_wol,
+ .get_link_ksettings = get_link_ksettings,
+ .set_link_ksettings = set_link_ksettings,
};
static int in_range(int val, int lo, int hi)
diff --git a/drivers/net/ethernet/cirrus/ep93xx_eth.c b/drivers/net/ethernet/cirrus/ep93xx_eth.c
index a1de0d12927d..396c88678eab 100644
--- a/drivers/net/ethernet/cirrus/ep93xx_eth.c
+++ b/drivers/net/ethernet/cirrus/ep93xx_eth.c
@@ -715,16 +715,18 @@ static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i
strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
}
-static int ep93xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int ep93xx_get_link_ksettings(struct net_device *dev,
+ struct ethtool_link_ksettings *cmd)
{
struct ep93xx_priv *ep = netdev_priv(dev);
- return mii_ethtool_gset(&ep->mii, cmd);
+ return mii_ethtool_get_link_ksettings(&ep->mii, cmd);
}
-static int ep93xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int ep93xx_set_link_ksettings(struct net_device *dev,
+ const struct ethtool_link_ksettings *cmd)
{
struct ep93xx_priv *ep = netdev_priv(dev);
- return mii_ethtool_sset(&ep->mii, cmd);
+ return mii_ethtool_set_link_ksettings(&ep->mii, cmd);
}
static int ep93xx_nway_reset(struct net_device *dev)
@@ -741,10 +743,10 @@ static u32 ep93xx_get_link(struct net_device *dev)
static const struct ethtool_ops ep93xx_ethtool_ops = {
.get_drvinfo = ep93xx_get_drvinfo,
- .get_settings = ep93xx_get_settings,
- .set_settings = ep93xx_set_settings,
.nway_reset = ep93xx_nway_reset,
.get_link = ep93xx_get_link,
+ .get_link_ksettings = ep93xx_get_link_ksettings,
+ .set_link_ksettings = ep93xx_set_link_ksettings,
};
static const struct net_device_ops ep93xx_netdev_ops = {
diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c
index f1a81c52afe3..008dc8161775 100644
--- a/drivers/net/ethernet/davicom/dm9000.c
+++ b/drivers/net/ethernet/davicom/dm9000.c
@@ -570,19 +570,21 @@ static void dm9000_set_msglevel(struct net_device *dev, u32 value)
dm->msg_enable = value;
}
-static int dm9000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int dm9000_get_link_ksettings(struct net_device *dev,
+ struct ethtool_link_ksettings *cmd)
{
struct board_info *dm = to_dm9000_board(dev);
- mii_ethtool_gset(&dm->mii, cmd);
+ mii_ethtool_get_link_ksettings(&dm->mii, cmd);
return 0;
}
-static int dm9000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int dm9000_set_link_ksettings(struct net_device *dev,
+ const struct ethtool_link_ksettings *cmd)
{
struct board_info *dm = to_dm9000_board(dev);
- return mii_ethtool_sset(&dm->mii, cmd);
+ return mii_ethtool_set_link_ksettings(&dm->mii, cmd);
}
static int dm9000_nway_reset(struct net_device *dev)
@@ -741,8 +743,6 @@ static int dm9000_set_wol(struct net_device *dev, struct ethtool_wolinfo *w)
static const struct ethtool_ops dm9000_ethtool_ops = {
.get_drvinfo = dm9000_get_drvinfo,
- .get_settings = dm9000_get_settings,
- .set_settings = dm9000_set_settings,
.get_msglevel = dm9000_get_msglevel,
.set_msglevel = dm9000_set_msglevel,
.nway_reset = dm9000_nway_reset,
@@ -752,6 +752,8 @@ static const struct ethtool_ops dm9000_ethtool_ops = {
.get_eeprom_len = dm9000_get_eeprom_len,
.get_eeprom = dm9000_get_eeprom,
.set_eeprom = dm9000_set_eeprom,
+ .get_link_ksettings = dm9000_get_link_ksettings,
+ .set_link_ksettings = dm9000_set_link_ksettings,
};
static void dm9000_show_carrier(struct board_info *db,
diff --git a/drivers/net/ethernet/freescale/dpaa/Kconfig b/drivers/net/ethernet/freescale/dpaa/Kconfig
index f3a3454805f9..a654736237a9 100644
--- a/drivers/net/ethernet/freescale/dpaa/Kconfig
+++ b/drivers/net/ethernet/freescale/dpaa/Kconfig
@@ -1,6 +1,6 @@
menuconfig FSL_DPAA_ETH
tristate "DPAA Ethernet"
- depends on FSL_SOC && FSL_DPAA && FSL_FMAN
+ depends on FSL_DPAA && FSL_FMAN
select PHYLIB
select FSL_FMAN_MAC
---help---
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index 3c48a84dec86..624ba9058dc4 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -733,7 +733,7 @@ static int dpaa_eth_cgr_init(struct dpaa_priv *priv)
priv->cgr_data.cgr.cb = dpaa_eth_cgscn;
/* Enable Congestion State Change Notifications and CS taildrop */
- initcgr.we_mask = QM_CGR_WE_CSCN_EN | QM_CGR_WE_CS_THRES;
+ initcgr.we_mask = cpu_to_be16(QM_CGR_WE_CSCN_EN | QM_CGR_WE_CS_THRES);
initcgr.cgr.cscn_en = QM_CGR_EN;
/* Set different thresholds based on the MAC speed.
@@ -747,7 +747,7 @@ static int dpaa_eth_cgr_init(struct dpaa_priv *priv)
cs_th = DPAA_CS_THRESHOLD_1G;
qm_cgr_cs_thres_set64(&initcgr.cgr.cs_thres, cs_th, 1);
- initcgr.we_mask |= QM_CGR_WE_CSTD_EN;
+ initcgr.we_mask |= cpu_to_be16(QM_CGR_WE_CSTD_EN);
initcgr.cgr.cstd_en = QM_CGR_EN;
err = qman_create_cgr(&priv->cgr_data.cgr, QMAN_CGR_FLAG_USE_INIT,
@@ -896,18 +896,18 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable)
if (dpaa_fq->init) {
memset(&initfq, 0, sizeof(initfq));
- initfq.we_mask = QM_INITFQ_WE_FQCTRL;
+ initfq.we_mask = cpu_to_be16(QM_INITFQ_WE_FQCTRL);
/* Note: we may get to keep an empty FQ in cache */
- initfq.fqd.fq_ctrl = QM_FQCTRL_PREFERINCACHE;
+ initfq.fqd.fq_ctrl = cpu_to_be16(QM_FQCTRL_PREFERINCACHE);
/* Try to reduce the number of portal interrupts for
* Tx Confirmation FQs.
*/
if (dpaa_fq->fq_type == FQ_TYPE_TX_CONFIRM)
- initfq.fqd.fq_ctrl |= QM_FQCTRL_HOLDACTIVE;
+ initfq.fqd.fq_ctrl |= cpu_to_be16(QM_FQCTRL_HOLDACTIVE);
/* FQ placement */
- initfq.we_mask |= QM_INITFQ_WE_DESTWQ;
+ initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_DESTWQ);
qm_fqd_set_destwq(&initfq.fqd, dpaa_fq->channel, dpaa_fq->wq);
@@ -920,8 +920,8 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable)
if (dpaa_fq->fq_type == FQ_TYPE_TX ||
dpaa_fq->fq_type == FQ_TYPE_TX_CONFIRM ||
dpaa_fq->fq_type == FQ_TYPE_TX_CONF_MQ) {
- initfq.we_mask |= QM_INITFQ_WE_CGID;
- initfq.fqd.fq_ctrl |= QM_FQCTRL_CGE;
+ initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_CGID);
+ initfq.fqd.fq_ctrl |= cpu_to_be16(QM_FQCTRL_CGE);
initfq.fqd.cgid = (u8)priv->cgr_data.cgr.cgrid;
/* Set a fixed overhead accounting, in an attempt to
* reduce the impact of fixed-size skb shells and the
@@ -932,7 +932,7 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable)
* insufficient value, but even that is better than
* no overhead accounting at all.
*/
- initfq.we_mask |= QM_INITFQ_WE_OAC;
+ initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_OAC);
qm_fqd_set_oac(&initfq.fqd, QM_OAC_CG);
qm_fqd_set_oal(&initfq.fqd,
min(sizeof(struct sk_buff) +
@@ -941,9 +941,9 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable)
}
if (td_enable) {
- initfq.we_mask |= QM_INITFQ_WE_TDTHRESH;
+ initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_TDTHRESH);
qm_fqd_set_taildrop(&initfq.fqd, DPAA_FQ_TD, 1);
- initfq.fqd.fq_ctrl = QM_FQCTRL_TDE;
+ initfq.fqd.fq_ctrl = cpu_to_be16(QM_FQCTRL_TDE);
}
if (dpaa_fq->fq_type == FQ_TYPE_TX) {
@@ -951,7 +951,8 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable)
if (queue_id >= 0)
confq = priv->conf_fqs[queue_id];
if (confq) {
- initfq.we_mask |= QM_INITFQ_WE_CONTEXTA;
+ initfq.we_mask |=
+ cpu_to_be16(QM_INITFQ_WE_CONTEXTA);
/* ContextA: OVOM=1(use contextA2 bits instead of ICAD)
* A2V=1 (contextA A2 field is valid)
* A0V=1 (contextA A0 field is valid)
@@ -959,8 +960,8 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable)
* ContextA A2: EBD=1 (deallocate buffers inside FMan)
* ContextB B0(ASPID): 0 (absolute Virtual Storage ID)
*/
- initfq.fqd.context_a.hi = 0x1e000000;
- initfq.fqd.context_a.lo = 0x80000000;
+ qm_fqd_context_a_set64(&initfq.fqd,
+ 0x1e00000080000000ULL);
}
}
@@ -968,13 +969,13 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable)
if (priv->use_ingress_cgr &&
(dpaa_fq->fq_type == FQ_TYPE_RX_DEFAULT ||
dpaa_fq->fq_type == FQ_TYPE_RX_ERROR)) {
- initfq.we_mask |= QM_INITFQ_WE_CGID;
- initfq.fqd.fq_ctrl |= QM_FQCTRL_CGE;
+ initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_CGID);
+ initfq.fqd.fq_ctrl |= cpu_to_be16(QM_FQCTRL_CGE);
initfq.fqd.cgid = (u8)priv->ingress_cgr.cgrid;
/* Set a fixed overhead accounting, just like for the
* egress CGR.
*/
- initfq.we_mask |= QM_INITFQ_WE_OAC;
+ initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_OAC);
qm_fqd_set_oac(&initfq.fqd, QM_OAC_CG);
qm_fqd_set_oal(&initfq.fqd,
min(sizeof(struct sk_buff) +
@@ -984,9 +985,8 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable)
/* Initialization common to all ingress queues */
if (dpaa_fq->flags & QMAN_FQ_FLAG_NO_ENQUEUE) {
- initfq.we_mask |= QM_INITFQ_WE_CONTEXTA;
- initfq.fqd.fq_ctrl |=
- QM_FQCTRL_HOLDACTIVE;
+ initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_CONTEXTA);
+ initfq.fqd.fq_ctrl |= cpu_to_be16(QM_FQCTRL_HOLDACTIVE);
initfq.fqd.context_a.stashing.exclusive =
QM_STASHING_EXCL_DATA | QM_STASHING_EXCL_CTX |
QM_STASHING_EXCL_ANNOTATION;
@@ -1350,7 +1350,7 @@ static int dpaa_enable_tx_csum(struct dpaa_priv *priv,
parse_result->l4_off = (u8)skb_transport_offset(skb);
/* Enable L3 (and L4, if TCP or UDP) HW checksum. */
- fd->cmd |= FM_FD_CMD_RPD | FM_FD_CMD_DTC;
+ fd->cmd |= cpu_to_be32(FM_FD_CMD_RPD | FM_FD_CMD_DTC);
/* On P1023 and similar platforms fd->cmd interpretation could
* be disabled by setting CONTEXT_A bit ICMD; currently this bit
@@ -1732,7 +1732,7 @@ static int skb_to_contig_fd(struct dpaa_priv *priv,
/* Fill in the rest of the FD fields */
qm_fd_set_contig(fd, priv->tx_headroom, skb->len);
- fd->cmd |= FM_FD_CMD_FCO;
+ fd->cmd |= cpu_to_be32(FM_FD_CMD_FCO);
/* Map the entire buffer size that may be seen by FMan, but no more */
addr = dma_map_single(dev, skbh,
@@ -1840,7 +1840,7 @@ static int skb_to_sg_fd(struct dpaa_priv *priv,
}
fd->bpid = FSL_DPAA_BPID_INV;
- fd->cmd |= FM_FD_CMD_FCO;
+ fd->cmd |= cpu_to_be32(FM_FD_CMD_FCO);
qm_fd_addr_set64(fd, addr);
return 0;
@@ -1867,7 +1867,7 @@ static inline int dpaa_xmit(struct dpaa_priv *priv,
egress_fq = priv->egress_fqs[queue];
if (fd->bpid == FSL_DPAA_BPID_INV)
- fd->cmd |= qman_fq_fqid(priv->conf_fqs[queue]);
+ fd->cmd |= cpu_to_be32(qman_fq_fqid(priv->conf_fqs[queue]));
/* Trace this Tx fd */
trace_dpaa_tx_fd(priv->net_dev, egress_fq, fd);
@@ -1960,17 +1960,17 @@ static void dpaa_rx_error(struct net_device *net_dev,
{
if (net_ratelimit())
netif_err(priv, hw, net_dev, "Err FD status = 0x%08x\n",
- fd->status & FM_FD_STAT_RX_ERRORS);
+ be32_to_cpu(fd->status) & FM_FD_STAT_RX_ERRORS);
percpu_priv->stats.rx_errors++;
- if (fd->status & FM_FD_ERR_DMA)
+ if (be32_to_cpu(fd->status) & FM_FD_ERR_DMA)
percpu_priv->rx_errors.dme++;
- if (fd->status & FM_FD_ERR_PHYSICAL)
+ if (be32_to_cpu(fd->status) & FM_FD_ERR_PHYSICAL)
percpu_priv->rx_errors.fpe++;
- if (fd->status & FM_FD_ERR_SIZE)
+ if (be32_to_cpu(fd->status) & FM_FD_ERR_SIZE)
percpu_priv->rx_errors.fse++;
- if (fd->status & FM_FD_ERR_PRS_HDR_ERR)
+ if (be32_to_cpu(fd->status) & FM_FD_ERR_PRS_HDR_ERR)
percpu_priv->rx_errors.phe++;
dpaa_fd_release(net_dev, fd);
@@ -1986,7 +1986,7 @@ static void dpaa_tx_error(struct net_device *net_dev,
if (net_ratelimit())
netif_warn(priv, hw, net_dev, "FD status = 0x%08x\n",
- fd->status & FM_FD_STAT_TX_ERRORS);
+ be32_to_cpu(fd->status) & FM_FD_STAT_TX_ERRORS);
percpu_priv->stats.tx_errors++;
@@ -2020,10 +2020,11 @@ static void dpaa_tx_conf(struct net_device *net_dev,
{
struct sk_buff *skb;
- if (unlikely(fd->status & FM_FD_STAT_TX_ERRORS) != 0) {
+ if (unlikely(be32_to_cpu(fd->status) & FM_FD_STAT_TX_ERRORS)) {
if (net_ratelimit())
netif_warn(priv, hw, net_dev, "FD status = 0x%08x\n",
- fd->status & FM_FD_STAT_TX_ERRORS);
+ be32_to_cpu(fd->status) &
+ FM_FD_STAT_TX_ERRORS);
percpu_priv->stats.tx_errors++;
}
@@ -2100,6 +2101,8 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
struct sk_buff *skb;
int *count_ptr;
+ fd_status = be32_to_cpu(fd->status);
+ fd_format = qm_fd_get_format(fd);
net_dev = ((struct dpaa_fq *)fq)->net_dev;
priv = netdev_priv(net_dev);
dpaa_bp = dpaa_bpid2pool(dq->fd.bpid);
@@ -2417,12 +2420,12 @@ static int dpaa_ingress_cgr_init(struct dpaa_priv *priv)
}
/* Enable CS TD, but disable Congestion State Change Notifications. */
- initcgr.we_mask = QM_CGR_WE_CS_THRES;
+ initcgr.we_mask = cpu_to_be16(QM_CGR_WE_CS_THRES);
initcgr.cgr.cscn_en = QM_CGR_EN;
cs_th = DPAA_INGRESS_CS_THRESHOLD;
qm_cgr_cs_thres_set64(&initcgr.cgr.cs_thres, cs_th, 1);
- initcgr.we_mask |= QM_CGR_WE_CSTD_EN;
+ initcgr.we_mask |= cpu_to_be16(QM_CGR_WE_CSTD_EN);
initcgr.cgr.cstd_en = QM_CGR_EN;
/* This CGR will be associated with the SWP affined to the current CPU.
diff --git a/drivers/net/ethernet/freescale/fman/Kconfig b/drivers/net/ethernet/freescale/fman/Kconfig
index 79b7c84b7869..dc0850b3b517 100644
--- a/drivers/net/ethernet/freescale/fman/Kconfig
+++ b/drivers/net/ethernet/freescale/fman/Kconfig
@@ -1,6 +1,6 @@
config FSL_FMAN
tristate "FMan support"
- depends on FSL_SOC || COMPILE_TEST
+ depends on FSL_SOC || ARCH_LAYERSCAPE || COMPILE_TEST
select GENERIC_ALLOCATOR
select PHYLIB
default n
diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c
index dafd9e1baba2..f60845f0c6ca 100644
--- a/drivers/net/ethernet/freescale/fman/fman.c
+++ b/drivers/net/ethernet/freescale/fman/fman.c
@@ -1890,6 +1890,7 @@ static int fman_reset(struct fman *fman)
goto _return;
} else {
+#ifdef CONFIG_PPC
struct device_node *guts_node;
struct ccsr_guts __iomem *guts_regs;
u32 devdisr2, reg;
@@ -1921,6 +1922,7 @@ static int fman_reset(struct fman *fman)
/* Enable all MACs */
iowrite32be(reg, &guts_regs->devdisr2);
+#endif
/* Perform FMan reset */
iowrite32be(FPM_RSTC_FM_RESET, &fman->fpm_regs->fm_rstc);
@@ -1932,25 +1934,31 @@ static int fman_reset(struct fman *fman)
} while (((ioread32be(&fman->fpm_regs->fm_rstc)) &
FPM_RSTC_FM_RESET) && --count);
if (count == 0) {
+#ifdef CONFIG_PPC
iounmap(guts_regs);
of_node_put(guts_node);
+#endif
err = -EBUSY;
goto _return;
}
+#ifdef CONFIG_PPC
/* Restore devdisr2 value */
iowrite32be(devdisr2, &guts_regs->devdisr2);
iounmap(guts_regs);
of_node_put(guts_node);
+#endif
goto _return;
+#ifdef CONFIG_PPC
guts_regs:
of_node_put(guts_node);
guts_node:
dev_dbg(fman->dev, "%s: Didn't perform FManV3 reset due to Errata A007273!\n",
__func__);
+#endif
}
_return:
return err;
@@ -2868,6 +2876,13 @@ static struct fman *read_dts_node(struct platform_device *of_dev)
fman->dev = &of_dev->dev;
+ err = of_platform_populate(fm_node, NULL, NULL, &of_dev->dev);
+ if (err) {
+ dev_err(&of_dev->dev, "%s: of_platform_populate() failed\n",
+ __func__);
+ goto fman_free;
+ }
+
return fman;
fman_node_put:
diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c
index 69ca42ce5dd5..0b31f8502ada 100644
--- a/drivers/net/ethernet/freescale/fman/mac.c
+++ b/drivers/net/ethernet/freescale/fman/mac.c
@@ -594,6 +594,7 @@ static const u16 phy2speed[] = {
[PHY_INTERFACE_MODE_RGMII_RXID] = SPEED_1000,
[PHY_INTERFACE_MODE_RGMII_TXID] = SPEED_1000,
[PHY_INTERFACE_MODE_RTBI] = SPEED_1000,
+ [PHY_INTERFACE_MODE_QSGMII] = SPEED_1000,
[PHY_INTERFACE_MODE_XGMII] = SPEED_10000
};
diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c
index 854befde0a08..97b184774784 100644
--- a/drivers/net/ethernet/hisilicon/hip04_eth.c
+++ b/drivers/net/ethernet/hisilicon/hip04_eth.c
@@ -828,6 +828,7 @@ static int hip04_mac_probe(struct platform_device *pdev)
priv = netdev_priv(ndev);
priv->ndev = ndev;
platform_set_drvdata(pdev, ndev);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->base = devm_ioremap_resource(d, res);
@@ -903,7 +904,6 @@ static int hip04_mac_probe(struct platform_device *pdev)
ndev->priv_flags |= IFF_UNICAST_FLT;
ndev->irq = irq;
netif_napi_add(ndev, &priv->napi, hip04_rx_poll, NAPI_POLL_WEIGHT);
- SET_NETDEV_DEV(ndev, &pdev->dev);
hip04_reset_ppe(priv);
if (priv->phy_mode == PHY_INTERFACE_MODE_MII)
diff --git a/drivers/net/ethernet/hisilicon/hisi_femac.c b/drivers/net/ethernet/hisilicon/hisi_femac.c
index 49863068c59e..979852d56f31 100644
--- a/drivers/net/ethernet/hisilicon/hisi_femac.c
+++ b/drivers/net/ethernet/hisilicon/hisi_femac.c
@@ -805,6 +805,7 @@ static int hisi_femac_drv_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, ndev);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
priv = netdev_priv(ndev);
priv->dev = dev;
@@ -882,7 +883,6 @@ static int hisi_femac_drv_probe(struct platform_device *pdev)
ndev->netdev_ops = &hisi_femac_netdev_ops;
ndev->ethtool_ops = &hisi_femac_ethtools_ops;
netif_napi_add(ndev, &priv->napi, hisi_femac_poll, FEMAC_POLL_WEIGHT);
- SET_NETDEV_DEV(ndev, &pdev->dev);
hisi_femac_port_init(priv);
diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
index ee7e9ce2f5b3..418ca1f3774a 100644
--- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
@@ -1316,10 +1316,11 @@ static int hix5hd2_dev_remove(struct platform_device *pdev)
}
static const struct of_device_id hix5hd2_of_match[] = {
- { .compatible = "hisilicon,hisi-gemac-v1", .data = (void *)GEMAC_V1 },
- { .compatible = "hisilicon,hisi-gemac-v2", .data = (void *)GEMAC_V2 },
- { .compatible = "hisilicon,hix5hd2-gemac", .data = (void *)GEMAC_V1 },
- { .compatible = "hisilicon,hi3798cv200-gemac", .data = (void *)GEMAC_V2 },
+ { .compatible = "hisilicon,hisi-gmac-v1", .data = (void *)GEMAC_V1 },
+ { .compatible = "hisilicon,hisi-gmac-v2", .data = (void *)GEMAC_V2 },
+ { .compatible = "hisilicon,hix5hd2-gmac", .data = (void *)GEMAC_V1 },
+ { .compatible = "hisilicon,hi3798cv200-gmac", .data = (void *)GEMAC_V2 },
+ { .compatible = "hisilicon,hi3516a-gmac", .data = (void *)GEMAC_V2 },
{},
};
@@ -1327,7 +1328,7 @@ MODULE_DEVICE_TABLE(of, hix5hd2_of_match);
static struct platform_driver hix5hd2_dev_driver = {
.driver = {
- .name = "hisi-gemac",
+ .name = "hisi-gmac",
.of_match_table = hix5hd2_of_match,
},
.probe = hix5hd2_dev_probe,
@@ -1338,4 +1339,4 @@ module_platform_driver(hix5hd2_dev_driver);
MODULE_DESCRIPTION("HISILICON Gigabit Ethernet MAC driver");
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:hisi-gemac");
+MODULE_ALIAS("platform:hisi-gmac");
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index fbece63395a8..a831f947ca8c 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -1181,7 +1181,9 @@ map_failed:
static void ibmveth_rx_mss_helper(struct sk_buff *skb, u16 mss, int lrg_pkt)
{
+ struct tcphdr *tcph;
int offset = 0;
+ int hdr_len;
/* only TCP packets will be aggregated */
if (skb->protocol == htons(ETH_P_IP)) {
@@ -1208,14 +1210,20 @@ static void ibmveth_rx_mss_helper(struct sk_buff *skb, u16 mss, int lrg_pkt)
/* if mss is not set through Large Packet bit/mss in rx buffer,
* expect that the mss will be written to the tcp header checksum.
*/
+ tcph = (struct tcphdr *)(skb->data + offset);
if (lrg_pkt) {
skb_shinfo(skb)->gso_size = mss;
} else if (offset) {
- struct tcphdr *tcph = (struct tcphdr *)(skb->data + offset);
-
skb_shinfo(skb)->gso_size = ntohs(tcph->check);
tcph->check = 0;
}
+
+ if (skb_shinfo(skb)->gso_size) {
+ hdr_len = offset + tcph->doff * 4;
+ skb_shinfo(skb)->gso_segs =
+ DIV_ROUND_UP(skb->len - hdr_len,
+ skb_shinfo(skb)->gso_size);
+ }
}
static int ibmveth_poll(struct napi_struct *napi, int budget)
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 5f62c3d70df9..1fa7c03edec2 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -2713,7 +2713,7 @@ static const struct of_device_id mv643xx_eth_shared_ids[] = {
MODULE_DEVICE_TABLE(of, mv643xx_eth_shared_ids);
#endif
-#if defined(CONFIG_OF) && !defined(CONFIG_MV64X60)
+#if defined(CONFIG_OF_IRQ) && !defined(CONFIG_MV64X60)
#define mv643xx_eth_property(_np, _name, _v) \
do { \
u32 tmp; \
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
index 3b026c151cf2..7431f633de31 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
@@ -75,7 +75,7 @@ static void mlx5_fc_stats_insert(struct rb_root *root, struct mlx5_fc *counter)
struct rb_node *parent = NULL;
while (*new) {
- struct mlx5_fc *this = container_of(*new, struct mlx5_fc, node);
+ struct mlx5_fc *this = rb_entry(*new, struct mlx5_fc, node);
int result = counter->id - this->id;
parent = *new;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index fece974b4edd..d768c7b6c6d6 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -2404,7 +2404,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
local_port);
return err;
}
- err = __mlxsw_sp_port_create(mlxsw_sp, local_port, false,
+ err = __mlxsw_sp_port_create(mlxsw_sp, local_port, split,
module, width, lane);
if (err)
goto err_port_create;
diff --git a/drivers/net/ethernet/microchip/encx24j600-regmap.c b/drivers/net/ethernet/microchip/encx24j600-regmap.c
index f3bb9055a292..44bb04d4d21b 100644
--- a/drivers/net/ethernet/microchip/encx24j600-regmap.c
+++ b/drivers/net/ethernet/microchip/encx24j600-regmap.c
@@ -26,11 +26,11 @@ static inline bool is_bits_set(int value, int mask)
}
static int encx24j600_switch_bank(struct encx24j600_context *ctx,
- int bank)
+ int bank)
{
int ret = 0;
-
int bank_opcode = BANK_SELECT(bank);
+
ret = spi_write(ctx->spi, &bank_opcode, 1);
if (ret == 0)
ctx->bank = bank;
@@ -39,7 +39,7 @@ static int encx24j600_switch_bank(struct encx24j600_context *ctx,
}
static int encx24j600_cmdn(struct encx24j600_context *ctx, u8 opcode,
- const void *buf, size_t len)
+ const void *buf, size_t len)
{
struct spi_message m;
struct spi_transfer t[2] = { { .tx_buf = &opcode, .len = 1, },
@@ -54,12 +54,14 @@ static int encx24j600_cmdn(struct encx24j600_context *ctx, u8 opcode,
static void regmap_lock_mutex(void *context)
{
struct encx24j600_context *ctx = context;
+
mutex_lock(&ctx->mutex);
}
static void regmap_unlock_mutex(void *context)
{
struct encx24j600_context *ctx = context;
+
mutex_unlock(&ctx->mutex);
}
@@ -128,6 +130,7 @@ static int regmap_encx24j600_sfr_update(struct encx24j600_context *ctx,
if (reg < 0x80) {
int ret = 0;
+
cmd = banked_code | banked_reg;
if ((banked_reg < 0x16) && (ctx->bank != bank))
ret = encx24j600_switch_bank(ctx, bank);
@@ -174,6 +177,7 @@ static int regmap_encx24j600_sfr_write(void *context, u8 reg, u8 *val,
size_t len)
{
struct encx24j600_context *ctx = context;
+
return regmap_encx24j600_sfr_update(ctx, reg, val, len, WCRU, WCRCODE);
}
@@ -228,9 +232,9 @@ int regmap_encx24j600_spi_write(void *context, u8 reg, const u8 *data,
if (reg < 0xc0)
return encx24j600_cmdn(ctx, reg, data, count);
- else
- /* SPI 1-byte command. Ignore data */
- return spi_write(ctx->spi, &reg, 1);
+
+ /* SPI 1-byte command. Ignore data */
+ return spi_write(ctx->spi, &reg, 1);
}
EXPORT_SYMBOL_GPL(regmap_encx24j600_spi_write);
@@ -495,6 +499,7 @@ static struct regmap_config phycfg = {
.writeable_reg = encx24j600_phymap_writeable,
.volatile_reg = encx24j600_phymap_volatile,
};
+
static struct regmap_bus phymap_encx24j600 = {
.reg_write = regmap_encx24j600_phy_reg_write,
.reg_read = regmap_encx24j600_phy_reg_read,
diff --git a/drivers/net/ethernet/microchip/encx24j600.c b/drivers/net/ethernet/microchip/encx24j600.c
index b14f0305aa31..fbce6166504e 100644
--- a/drivers/net/ethernet/microchip/encx24j600.c
+++ b/drivers/net/ethernet/microchip/encx24j600.c
@@ -30,7 +30,7 @@
#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
static int debug = -1;
-module_param(debug, int, 0);
+module_param(debug, int, 0000);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
/* SRAM memory layout:
@@ -105,6 +105,7 @@ static u16 encx24j600_read_reg(struct encx24j600_priv *priv, u8 reg)
struct net_device *dev = priv->ndev;
unsigned int val = 0;
int ret = regmap_read(priv->ctx.regmap, reg, &val);
+
if (unlikely(ret))
netif_err(priv, drv, dev, "%s: error %d reading reg %02x\n",
__func__, ret, reg);
@@ -115,6 +116,7 @@ static void encx24j600_write_reg(struct encx24j600_priv *priv, u8 reg, u16 val)
{
struct net_device *dev = priv->ndev;
int ret = regmap_write(priv->ctx.regmap, reg, val);
+
if (unlikely(ret))
netif_err(priv, drv, dev, "%s: error %d writing reg %02x=%04x\n",
__func__, ret, reg, val);
@@ -125,6 +127,7 @@ static void encx24j600_update_reg(struct encx24j600_priv *priv, u8 reg,
{
struct net_device *dev = priv->ndev;
int ret = regmap_update_bits(priv->ctx.regmap, reg, mask, val);
+
if (unlikely(ret))
netif_err(priv, drv, dev, "%s: error %d updating reg %02x=%04x~%04x\n",
__func__, ret, reg, val, mask);
@@ -135,6 +138,7 @@ static u16 encx24j600_read_phy(struct encx24j600_priv *priv, u8 reg)
struct net_device *dev = priv->ndev;
unsigned int val = 0;
int ret = regmap_read(priv->ctx.phymap, reg, &val);
+
if (unlikely(ret))
netif_err(priv, drv, dev, "%s: error %d reading %02x\n",
__func__, ret, reg);
@@ -145,6 +149,7 @@ static void encx24j600_write_phy(struct encx24j600_priv *priv, u8 reg, u16 val)
{
struct net_device *dev = priv->ndev;
int ret = regmap_write(priv->ctx.phymap, reg, val);
+
if (unlikely(ret))
netif_err(priv, drv, dev, "%s: error %d writing reg %02x=%04x\n",
__func__, ret, reg, val);
@@ -164,6 +169,7 @@ static void encx24j600_cmd(struct encx24j600_priv *priv, u8 cmd)
{
struct net_device *dev = priv->ndev;
int ret = regmap_write(priv->ctx.regmap, cmd, 0);
+
if (unlikely(ret))
netif_err(priv, drv, dev, "%s: error %d with cmd %02x\n",
__func__, ret, cmd);
@@ -173,6 +179,7 @@ static int encx24j600_raw_read(struct encx24j600_priv *priv, u8 reg, u8 *data,
size_t count)
{
int ret;
+
mutex_lock(&priv->ctx.mutex);
ret = regmap_encx24j600_spi_read(&priv->ctx, reg, data, count);
mutex_unlock(&priv->ctx.mutex);
@@ -184,6 +191,7 @@ static int encx24j600_raw_write(struct encx24j600_priv *priv, u8 reg,
const u8 *data, size_t count)
{
int ret;
+
mutex_lock(&priv->ctx.mutex);
ret = regmap_encx24j600_spi_write(&priv->ctx, reg, data, count);
mutex_unlock(&priv->ctx.mutex);
@@ -194,6 +202,7 @@ static int encx24j600_raw_write(struct encx24j600_priv *priv, u8 reg,
static void encx24j600_update_phcon1(struct encx24j600_priv *priv)
{
u16 phcon1 = encx24j600_read_phy(priv, PHCON1);
+
if (priv->autoneg == AUTONEG_ENABLE) {
phcon1 |= ANEN | RENEG;
} else {
@@ -328,6 +337,7 @@ static int encx24j600_receive_packet(struct encx24j600_priv *priv,
{
struct net_device *dev = priv->ndev;
struct sk_buff *skb = netdev_alloc_skb(dev, rsv->len + NET_IP_ALIGN);
+
if (!skb) {
pr_err_ratelimited("RX: OOM: packet dropped\n");
dev->stats.rx_dropped++;
@@ -346,7 +356,6 @@ static int encx24j600_receive_packet(struct encx24j600_priv *priv,
/* Maintain stats */
dev->stats.rx_packets++;
dev->stats.rx_bytes += rsv->len;
- priv->next_packet = rsv->next_packet;
netif_rx(skb);
@@ -383,6 +392,8 @@ static void encx24j600_rx_packets(struct encx24j600_priv *priv, u8 packet_count)
encx24j600_receive_packet(priv, &rsv);
}
+ priv->next_packet = rsv.next_packet;
+
newrxtail = priv->next_packet - 2;
if (newrxtail == ENC_RX_BUF_START)
newrxtail = SRAM_SIZE - 2;
@@ -827,6 +838,7 @@ static void encx24j600_set_multicast_list(struct net_device *dev)
static void encx24j600_hw_tx(struct encx24j600_priv *priv)
{
struct net_device *dev = priv->ndev;
+
netif_info(priv, tx_queued, dev, "TX Packet Len:%d\n",
priv->tx_skb->len);
@@ -894,7 +906,6 @@ static void encx24j600_tx_timeout(struct net_device *dev)
dev->stats.tx_errors++;
netif_wake_queue(dev);
- return;
}
static int encx24j600_get_regs_len(struct net_device *dev)
@@ -957,12 +968,14 @@ static int encx24j600_set_settings(struct net_device *dev,
static u32 encx24j600_get_msglevel(struct net_device *dev)
{
struct encx24j600_priv *priv = netdev_priv(dev);
+
return priv->msg_enable;
}
static void encx24j600_set_msglevel(struct net_device *dev, u32 val)
{
struct encx24j600_priv *priv = netdev_priv(dev);
+
priv->msg_enable = val;
}
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
index 00efb1c4c57e..17a70122df05 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
@@ -1265,7 +1265,7 @@ static const struct qed_iscsi_ops qed_iscsi_ops_pass = {
.get_stats = &qed_iscsi_stats,
};
-const struct qed_iscsi_ops *qed_get_iscsi_ops()
+const struct qed_iscsi_ops *qed_get_iscsi_ops(void)
{
return &qed_iscsi_ops_pass;
}
diff --git a/drivers/net/ethernet/qualcomm/emac/emac.c b/drivers/net/ethernet/qualcomm/emac/emac.c
index ae32f855e31b..422289c232bc 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac.c
+++ b/drivers/net/ethernet/qualcomm/emac/emac.c
@@ -460,6 +460,12 @@ static int emac_clks_phase1_init(struct platform_device *pdev,
{
int ret;
+ /* On ACPI platforms, clocks are controlled by firmware and/or
+ * ACPI, not by drivers.
+ */
+ if (has_acpi_companion(&pdev->dev))
+ return 0;
+
ret = emac_clks_get(pdev, adpt);
if (ret)
return ret;
@@ -485,6 +491,9 @@ static int emac_clks_phase2_init(struct platform_device *pdev,
{
int ret;
+ if (has_acpi_companion(&pdev->dev))
+ return 0;
+
ret = clk_set_rate(adpt->clk[EMAC_CLK_TX], 125000000);
if (ret)
return ret;
diff --git a/drivers/net/ethernet/rdc/r6040.c b/drivers/net/ethernet/rdc/r6040.c
index 4ff4e0491406..aa11b70b9ca4 100644
--- a/drivers/net/ethernet/rdc/r6040.c
+++ b/drivers/net/ethernet/rdc/r6040.c
@@ -472,8 +472,6 @@ static void r6040_down(struct net_device *dev)
iowrite16(adrp[0], ioaddr + MID_0L);
iowrite16(adrp[1], ioaddr + MID_0M);
iowrite16(adrp[2], ioaddr + MID_0H);
-
- phy_stop(dev->phydev);
}
static int r6040_close(struct net_device *dev)
@@ -481,12 +479,12 @@ static int r6040_close(struct net_device *dev)
struct r6040_private *lp = netdev_priv(dev);
struct pci_dev *pdev = lp->pdev;
- spin_lock_irq(&lp->lock);
+ phy_stop(dev->phydev);
napi_disable(&lp->napi);
netif_stop_queue(dev);
- r6040_down(dev);
- free_irq(dev->irq, dev);
+ spin_lock_irq(&lp->lock);
+ r6040_down(dev);
/* Free RX buffer */
r6040_free_rxbufs(dev);
@@ -496,6 +494,8 @@ static int r6040_close(struct net_device *dev)
spin_unlock_irq(&lp->lock);
+ free_irq(dev->irq, dev);
+
/* Free Descriptor memory */
if (lp->rx_ring) {
pci_free_consistent(pdev,
diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
index 46f7be85f5a3..2c032629c369 100644
--- a/drivers/net/ethernet/sfc/Kconfig
+++ b/drivers/net/ethernet/sfc/Kconfig
@@ -1,3 +1,20 @@
+#
+# Solarflare device configuration
+#
+
+config NET_VENDOR_SOLARFLARE
+ bool "Solarflare devices"
+ default y
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Solarflare devices. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_SOLARFLARE
+
config SFC
tristate "Solarflare SFC9000/SFC9100-family support"
depends on PCI
@@ -44,3 +61,7 @@ config SFC_MCDI_LOGGING
Driver-Interface) commands and responses, allowing debugging of
driver/firmware interaction. The tracing is actually enabled by
a sysfs file 'mcdi_logging' under the PCI device.
+
+source "drivers/net/ethernet/sfc/falcon/Kconfig"
+
+endif # NET_VENDOR_SOLARFLARE
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index f644216eda1b..87bdc56b4e3a 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -120,44 +120,53 @@ static int efx_ethtool_phys_id(struct net_device *net_dev,
}
/* This must be called with rtnl_lock held. */
-static int efx_ethtool_get_settings(struct net_device *net_dev,
- struct ethtool_cmd *ecmd)
+static int
+efx_ethtool_get_link_ksettings(struct net_device *net_dev,
+ struct ethtool_link_ksettings *cmd)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_link_state *link_state = &efx->link_state;
+ u32 supported;
mutex_lock(&efx->mac_lock);
- efx->phy_op->get_settings(efx, ecmd);
+ efx->phy_op->get_link_ksettings(efx, cmd);
mutex_unlock(&efx->mac_lock);
/* Both MACs support pause frames (bidirectional and respond-only) */
- ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+ ethtool_convert_link_mode_to_legacy_u32(&supported,
+ cmd->link_modes.supported);
+
+ supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
+ supported);
if (LOOPBACK_INTERNAL(efx)) {
- ethtool_cmd_speed_set(ecmd, link_state->speed);
- ecmd->duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF;
+ cmd->base.speed = link_state->speed;
+ cmd->base.duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF;
}
return 0;
}
/* This must be called with rtnl_lock held. */
-static int efx_ethtool_set_settings(struct net_device *net_dev,
- struct ethtool_cmd *ecmd)
+static int
+efx_ethtool_set_link_ksettings(struct net_device *net_dev,
+ const struct ethtool_link_ksettings *cmd)
{
struct efx_nic *efx = netdev_priv(net_dev);
int rc;
/* GMAC does not support 1000Mbps HD */
- if ((ethtool_cmd_speed(ecmd) == SPEED_1000) &&
- (ecmd->duplex != DUPLEX_FULL)) {
+ if ((cmd->base.speed == SPEED_1000) &&
+ (cmd->base.duplex != DUPLEX_FULL)) {
netif_dbg(efx, drv, efx->net_dev,
"rejecting unsupported 1000Mbps HD setting\n");
return -EINVAL;
}
mutex_lock(&efx->mac_lock);
- rc = efx->phy_op->set_settings(efx, ecmd);
+ rc = efx->phy_op->set_link_ksettings(efx, cmd);
mutex_unlock(&efx->mac_lock);
return rc;
}
@@ -1342,8 +1351,6 @@ static int efx_ethtool_get_module_info(struct net_device *net_dev,
}
const struct ethtool_ops efx_ethtool_ops = {
- .get_settings = efx_ethtool_get_settings,
- .set_settings = efx_ethtool_set_settings,
.get_drvinfo = efx_ethtool_get_drvinfo,
.get_regs_len = efx_ethtool_get_regs_len,
.get_regs = efx_ethtool_get_regs,
@@ -1373,4 +1380,6 @@ const struct ethtool_ops efx_ethtool_ops = {
.get_ts_info = efx_ethtool_get_ts_info,
.get_module_info = efx_ethtool_get_module_info,
.get_module_eeprom = efx_ethtool_get_module_eeprom,
+ .get_link_ksettings = efx_ethtool_get_link_ksettings,
+ .set_link_ksettings = efx_ethtool_set_link_ksettings,
};
diff --git a/drivers/net/ethernet/sfc/mcdi_port.c b/drivers/net/ethernet/sfc/mcdi_port.c
index 9dcd396784ae..c905971c5f3a 100644
--- a/drivers/net/ethernet/sfc/mcdi_port.c
+++ b/drivers/net/ethernet/sfc/mcdi_port.c
@@ -503,45 +503,59 @@ static void efx_mcdi_phy_remove(struct efx_nic *efx)
kfree(phy_data);
}
-static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+static void efx_mcdi_phy_get_link_ksettings(struct efx_nic *efx,
+ struct ethtool_link_ksettings *cmd)
{
struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN);
int rc;
-
- ecmd->supported =
- mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap);
- ecmd->advertising = efx->link_advertising;
- ethtool_cmd_speed_set(ecmd, efx->link_state.speed);
- ecmd->duplex = efx->link_state.fd;
- ecmd->port = mcdi_to_ethtool_media(phy_cfg->media);
- ecmd->phy_address = phy_cfg->port;
- ecmd->transceiver = XCVR_INTERNAL;
- ecmd->autoneg = !!(efx->link_advertising & ADVERTISED_Autoneg);
- ecmd->mdio_support = (efx->mdio.mode_support &
+ u32 supported, advertising, lp_advertising;
+
+ supported = mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap);
+ advertising = efx->link_advertising;
+ cmd->base.speed = efx->link_state.speed;
+ cmd->base.duplex = efx->link_state.fd;
+ cmd->base.port = mcdi_to_ethtool_media(phy_cfg->media);
+ cmd->base.phy_address = phy_cfg->port;
+ cmd->base.autoneg = !!(efx->link_advertising & ADVERTISED_Autoneg);
+ cmd->base.mdio_support = (efx->mdio.mode_support &
(MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22));
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
+ supported);
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
+ advertising);
+
BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
outbuf, sizeof(outbuf), NULL);
if (rc)
return;
- ecmd->lp_advertising =
+ lp_advertising =
mcdi_to_ethtool_cap(phy_cfg->media,
MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP));
+
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
+ lp_advertising);
}
-static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+static int
+efx_mcdi_phy_set_link_ksettings(struct efx_nic *efx,
+ const struct ethtool_link_ksettings *cmd)
{
struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
u32 caps;
int rc;
+ u32 advertising;
+
+ ethtool_convert_link_mode_to_legacy_u32(&advertising,
+ cmd->link_modes.advertising);
- if (ecmd->autoneg) {
- caps = (ethtool_to_mcdi_cap(ecmd->advertising) |
+ if (cmd->base.autoneg) {
+ caps = (ethtool_to_mcdi_cap(advertising) |
1 << MC_CMD_PHY_CAP_AN_LBN);
- } else if (ecmd->duplex) {
- switch (ethtool_cmd_speed(ecmd)) {
+ } else if (cmd->base.duplex) {
+ switch (cmd->base.speed) {
case 10: caps = 1 << MC_CMD_PHY_CAP_10FDX_LBN; break;
case 100: caps = 1 << MC_CMD_PHY_CAP_100FDX_LBN; break;
case 1000: caps = 1 << MC_CMD_PHY_CAP_1000FDX_LBN; break;
@@ -550,7 +564,7 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec
default: return -EINVAL;
}
} else {
- switch (ethtool_cmd_speed(ecmd)) {
+ switch (cmd->base.speed) {
case 10: caps = 1 << MC_CMD_PHY_CAP_10HDX_LBN; break;
case 100: caps = 1 << MC_CMD_PHY_CAP_100HDX_LBN; break;
case 1000: caps = 1 << MC_CMD_PHY_CAP_1000HDX_LBN; break;
@@ -563,9 +577,9 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec
if (rc)
return rc;
- if (ecmd->autoneg) {
+ if (cmd->base.autoneg) {
efx_link_set_advertising(
- efx, ecmd->advertising | ADVERTISED_Autoneg);
+ efx, advertising | ADVERTISED_Autoneg);
phy_cfg->forced_cap = 0;
} else {
efx_link_set_advertising(efx, 0);
@@ -812,8 +826,8 @@ static const struct efx_phy_operations efx_mcdi_phy_ops = {
.poll = efx_mcdi_phy_poll,
.fini = efx_port_dummy_op_void,
.remove = efx_mcdi_phy_remove,
- .get_settings = efx_mcdi_phy_get_settings,
- .set_settings = efx_mcdi_phy_set_settings,
+ .get_link_ksettings = efx_mcdi_phy_get_link_ksettings,
+ .set_link_ksettings = efx_mcdi_phy_set_link_ksettings,
.test_alive = efx_mcdi_phy_test_alive,
.run_tests = efx_mcdi_phy_run_tests,
.test_name = efx_mcdi_phy_test_name,
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index 8692e829b40f..1a635ced62d0 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -720,8 +720,8 @@ static inline bool efx_link_state_equal(const struct efx_link_state *left,
* @reconfigure: Reconfigure PHY (e.g. for new link parameters)
* @poll: Update @link_state and report whether it changed.
* Serialised by the mac_lock.
- * @get_settings: Get ethtool settings. Serialised by the mac_lock.
- * @set_settings: Set ethtool settings. Serialised by the mac_lock.
+ * @get_link_ksettings: Get ethtool settings. Serialised by the mac_lock.
+ * @set_link_ksettings: Set ethtool settings. Serialised by the mac_lock.
* @set_npage_adv: Set abilities advertised in (Extended) Next Page
* (only needed where AN bit is set in mmds)
* @test_alive: Test that PHY is 'alive' (online)
@@ -736,10 +736,10 @@ struct efx_phy_operations {
void (*remove) (struct efx_nic *efx);
int (*reconfigure) (struct efx_nic *efx);
bool (*poll) (struct efx_nic *efx);
- void (*get_settings) (struct efx_nic *efx,
- struct ethtool_cmd *ecmd);
- int (*set_settings) (struct efx_nic *efx,
- struct ethtool_cmd *ecmd);
+ void (*get_link_ksettings)(struct efx_nic *efx,
+ struct ethtool_link_ksettings *cmd);
+ int (*set_link_ksettings)(struct efx_nic *efx,
+ const struct ethtool_link_ksettings *cmd);
void (*set_npage_adv) (struct efx_nic *efx, u32);
int (*test_alive) (struct efx_nic *efx);
const char *(*test_name) (struct efx_nic *efx, unsigned int index);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
index a340fc8bd0de..8816515e1bbb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
@@ -334,7 +334,7 @@ static void dwmac4_rd_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
* descriptors for the same frame has to be set before, to
* avoid race condition.
*/
- wmb();
+ dma_wmb();
p->des3 = cpu_to_le32(tdes3);
}
@@ -377,7 +377,7 @@ static void dwmac4_rd_prepare_tso_tx_desc(struct dma_desc *p, int is_fs,
* descriptors for the same frame has to be set before, to
* avoid race condition.
*/
- wmb();
+ dma_wmb();
p->des3 = cpu_to_le32(tdes3);
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index ce97e522566a..f0d86321dfe2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -350,7 +350,7 @@ static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
* descriptors for the same frame has to be set before, to
* avoid race condition.
*/
- wmb();
+ dma_wmb();
p->des0 = cpu_to_le32(tdes0);
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 3e405785b81c..bb40382e205d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2125,7 +2125,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
* descriptor and then barrier is needed to make sure that
* all is coherent before granting the DMA engine.
*/
- smp_wmb();
+ dma_wmb();
if (netif_msg_pktdata(priv)) {
pr_info("%s: curr=%d dirty=%d f=%d, e=%d, f_p=%p, nfrags %d\n",
@@ -2338,7 +2338,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
* descriptor and then barrier is needed to make sure that
* all is coherent before granting the DMA engine.
*/
- smp_wmb();
+ dma_wmb();
}
netdev_sent_queue(dev, skb->len);
@@ -2443,14 +2443,14 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
netif_dbg(priv, rx_status, priv->dev,
"refill entry #%d\n", entry);
}
- wmb();
+ dma_wmb();
if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00))
priv->hw->desc->init_rx_desc(p, priv->use_riwt, 0, 0);
else
priv->hw->desc->set_rx_owner(p);
- wmb();
+ dma_wmb();
entry = STMMAC_GET_ENTRY(entry, DMA_RX_SIZE);
}
diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c
index c7e547e4f2b1..7d9e36f66735 100644
--- a/drivers/net/ethernet/ti/netcp_ethss.c
+++ b/drivers/net/ethernet/ti/netcp_ethss.c
@@ -94,6 +94,7 @@
/* offset relative to base of XGBE_SS_REG_INDEX */
#define XGBE10_SGMII_MODULE_OFFSET 0x100
+#define IS_SS_ID_XGBE(d) ((d)->ss_version == XGBE_SS_VERSION_10)
/* offset relative to base of XGBE_SM_REG_INDEX */
#define XGBE10_HOST_PORT_OFFSET 0x34
#define XGBE10_SLAVE_PORT_OFFSET 0x64
@@ -1746,6 +1747,17 @@ static void keystone_set_msglevel(struct net_device *ndev, u32 value)
netcp->msg_enable = value;
}
+static struct gbe_intf *keystone_get_intf_data(struct netcp_intf *netcp)
+{
+ struct gbe_intf *gbe_intf;
+
+ gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+ if (!gbe_intf)
+ gbe_intf = netcp_module_get_intf_data(&xgbe_module, netcp);
+
+ return gbe_intf;
+}
+
static void keystone_get_stat_strings(struct net_device *ndev,
uint32_t stringset, uint8_t *data)
{
@@ -1754,7 +1766,7 @@ static void keystone_get_stat_strings(struct net_device *ndev,
struct gbe_priv *gbe_dev;
int i;
- gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+ gbe_intf = keystone_get_intf_data(netcp);
if (!gbe_intf)
return;
gbe_dev = gbe_intf->gbe_dev;
@@ -1778,7 +1790,7 @@ static int keystone_get_sset_count(struct net_device *ndev, int stringset)
struct gbe_intf *gbe_intf;
struct gbe_priv *gbe_dev;
- gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+ gbe_intf = keystone_get_intf_data(netcp);
if (!gbe_intf)
return -EINVAL;
gbe_dev = gbe_intf->gbe_dev;
@@ -1896,7 +1908,7 @@ static void keystone_get_ethtool_stats(struct net_device *ndev,
struct gbe_intf *gbe_intf;
struct gbe_priv *gbe_dev;
- gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+ gbe_intf = keystone_get_intf_data(netcp);
if (!gbe_intf)
return;
@@ -1920,7 +1932,7 @@ static int keystone_get_link_ksettings(struct net_device *ndev,
if (!phy)
return -EINVAL;
- gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+ gbe_intf = keystone_get_intf_data(netcp);
if (!gbe_intf)
return -EINVAL;
@@ -1953,7 +1965,7 @@ static int keystone_set_link_ksettings(struct net_device *ndev,
if (!phy)
return -EINVAL;
- gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+ gbe_intf = keystone_get_intf_data(netcp);
if (!gbe_intf)
return -EINVAL;
@@ -2311,7 +2323,7 @@ static void gbe_init_host_port(struct gbe_priv *priv)
int bypass_en = 1;
/* Host Tx Pri */
- if (IS_SS_ID_NU(priv))
+ if (IS_SS_ID_NU(priv) || IS_SS_ID_XGBE(priv))
writel(HOST_TX_PRI_MAP_DEFAULT,
GBE_REG_ADDR(priv, host_port_regs, tx_pri_map));
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 98f10c216521..8b6810bad54b 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -158,9 +158,9 @@ static bool gtp_check_src_ms_ipv4(struct sk_buff *skb, struct pdp_ctx *pctx,
if (!pskb_may_pull(skb, hdrlen + sizeof(struct iphdr)))
return false;
- iph = (struct iphdr *)(skb->data + hdrlen + sizeof(struct iphdr));
+ iph = (struct iphdr *)(skb->data + hdrlen);
- return iph->saddr != pctx->ms_addr_ip4.s_addr;
+ return iph->saddr == pctx->ms_addr_ip4.s_addr;
}
/* Check if the inner IP source address in this packet is assigned to any
@@ -423,11 +423,11 @@ static inline void gtp1_push_header(struct sk_buff *skb, struct pdp_ctx *pctx)
/* Bits 8 7 6 5 4 3 2 1
* +--+--+--+--+--+--+--+--+
- * |version |PT| 1| E| S|PN|
+ * |version |PT| 0| E| S|PN|
* +--+--+--+--+--+--+--+--+
* 0 0 1 1 1 0 0 0
*/
- gtp1->flags = 0x38; /* v1, GTP-non-prime. */
+ gtp1->flags = 0x30; /* v1, GTP-non-prime. */
gtp1->type = GTP_TPDU;
gtp1->length = htons(payload_len);
gtp1->tid = htonl(pctx->u.v1.o_tei);
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index f293d33fb28f..8d5b903d1d9d 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -517,9 +517,9 @@ static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb,
mtt = irda_get_mtt(skb);
pr_debug("%s: %ld, mtt=%d\n", __func__, jiffies, mtt);
- if (mtt > 1000)
- mdelay(mtt / 1000);
- else if (mtt)
+ if (mtt > 1000)
+ mdelay(mtt / 1000);
+ else if (mtt)
udelay(mtt);
/* Enable DMA interrupt */
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 9c06f8028f0c..92b08383cafa 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1187,8 +1187,8 @@ static int genphy_config_advert(struct phy_device *phydev)
*/
static int genphy_config_eee_advert(struct phy_device *phydev)
{
- u32 broken = phydev->eee_broken_modes;
- u32 old_adv, adv;
+ int broken = phydev->eee_broken_modes;
+ int old_adv, adv;
/* Nothing to disable */
if (!broken)
@@ -1665,7 +1665,7 @@ static void of_set_phy_supported(struct phy_device *phydev)
static void of_set_phy_eee_broken(struct phy_device *phydev)
{
struct device_node *node = phydev->mdio.dev.of_node;
- u32 broken;
+ u32 broken = 0;
if (!IS_ENABLED(CONFIG_OF_MDIO))
return;
@@ -1673,8 +1673,20 @@ static void of_set_phy_eee_broken(struct phy_device *phydev)
if (!node)
return;
- if (!of_property_read_u32(node, "eee-broken-modes", &broken))
- phydev->eee_broken_modes = broken;
+ if (of_property_read_bool(node, "eee-broken-100tx"))
+ broken |= MDIO_EEE_100TX;
+ if (of_property_read_bool(node, "eee-broken-1000t"))
+ broken |= MDIO_EEE_1000T;
+ if (of_property_read_bool(node, "eee-broken-10gt"))
+ broken |= MDIO_EEE_10GT;
+ if (of_property_read_bool(node, "eee-broken-1000kx"))
+ broken |= MDIO_EEE_1000KX;
+ if (of_property_read_bool(node, "eee-broken-10gkx4"))
+ broken |= MDIO_EEE_10GKX4;
+ if (of_property_read_bool(node, "eee-broken-10gkr"))
+ broken |= MDIO_EEE_10GKR;
+
+ phydev->eee_broken_modes = broken;
}
/**
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index b425fa1013af..08327e005ccc 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/virtio.h>
#include <linux/virtio_net.h>
+#include <linux/bpf.h>
#include <linux/scatterlist.h>
#include <linux/if_vlan.h>
#include <linux/slab.h>
@@ -81,6 +82,8 @@ struct receive_queue {
struct napi_struct napi;
+ struct bpf_prog __rcu *xdp_prog;
+
/* Chain pages by the private ptr. */
struct page *pages;
@@ -111,6 +114,9 @@ struct virtnet_info {
/* # of queue pairs currently used by the driver */
u16 curr_queue_pairs;
+ /* # of XDP queue pairs currently used by the driver */
+ u16 xdp_queue_pairs;
+
/* I like... big packets and I cannot lie! */
bool big_packets;
@@ -324,6 +330,90 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
return skb;
}
+static void virtnet_xdp_xmit(struct virtnet_info *vi,
+ struct receive_queue *rq,
+ struct send_queue *sq,
+ struct xdp_buff *xdp)
+{
+ struct page *page = virt_to_head_page(xdp->data);
+ struct virtio_net_hdr_mrg_rxbuf *hdr;
+ unsigned int num_sg, len;
+ void *xdp_sent;
+ int err;
+
+ /* Free up any pending old buffers before queueing new ones. */
+ while ((xdp_sent = virtqueue_get_buf(sq->vq, &len)) != NULL) {
+ struct page *sent_page = virt_to_head_page(xdp_sent);
+
+ if (vi->mergeable_rx_bufs)
+ put_page(sent_page);
+ else
+ give_pages(rq, sent_page);
+ }
+
+ /* Zero header and leave csum up to XDP layers */
+ hdr = xdp->data;
+ memset(hdr, 0, vi->hdr_len);
+
+ num_sg = 1;
+ sg_init_one(sq->sg, xdp->data, xdp->data_end - xdp->data);
+ err = virtqueue_add_outbuf(sq->vq, sq->sg, num_sg,
+ xdp->data, GFP_ATOMIC);
+ if (unlikely(err)) {
+ if (vi->mergeable_rx_bufs)
+ put_page(page);
+ else
+ give_pages(rq, page);
+ return; // On error abort to avoid unnecessary kick
+ } else if (!vi->mergeable_rx_bufs) {
+ /* If not mergeable bufs must be big packets so cleanup pages */
+ give_pages(rq, (struct page *)page->private);
+ page->private = 0;
+ }
+
+ virtqueue_kick(sq->vq);
+}
+
+static u32 do_xdp_prog(struct virtnet_info *vi,
+ struct receive_queue *rq,
+ struct bpf_prog *xdp_prog,
+ struct page *page, int offset, int len)
+{
+ int hdr_padded_len;
+ struct xdp_buff xdp;
+ unsigned int qp;
+ u32 act;
+ u8 *buf;
+
+ buf = page_address(page) + offset;
+
+ if (vi->mergeable_rx_bufs)
+ hdr_padded_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ else
+ hdr_padded_len = sizeof(struct padded_vnet_hdr);
+
+ xdp.data = buf + hdr_padded_len;
+ xdp.data_end = xdp.data + (len - vi->hdr_len);
+
+ act = bpf_prog_run_xdp(xdp_prog, &xdp);
+ switch (act) {
+ case XDP_PASS:
+ return XDP_PASS;
+ case XDP_TX:
+ qp = vi->curr_queue_pairs -
+ vi->xdp_queue_pairs +
+ smp_processor_id();
+ xdp.data = buf + (vi->mergeable_rx_bufs ? 0 : 4);
+ virtnet_xdp_xmit(vi, rq, &vi->sq[qp], &xdp);
+ return XDP_TX;
+ default:
+ bpf_warn_invalid_xdp_action(act);
+ case XDP_ABORTED:
+ case XDP_DROP:
+ return XDP_DROP;
+ }
+}
+
static struct sk_buff *receive_small(struct virtnet_info *vi, void *buf, unsigned int len)
{
struct sk_buff * skb = buf;
@@ -340,17 +430,102 @@ static struct sk_buff *receive_big(struct net_device *dev,
void *buf,
unsigned int len)
{
+ struct bpf_prog *xdp_prog;
struct page *page = buf;
- struct sk_buff *skb = page_to_skb(vi, rq, page, 0, len, PAGE_SIZE);
+ struct sk_buff *skb;
+ rcu_read_lock();
+ xdp_prog = rcu_dereference(rq->xdp_prog);
+ if (xdp_prog) {
+ struct virtio_net_hdr_mrg_rxbuf *hdr = buf;
+ u32 act;
+
+ if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags))
+ goto err_xdp;
+ act = do_xdp_prog(vi, rq, xdp_prog, page, 0, len);
+ switch (act) {
+ case XDP_PASS:
+ break;
+ case XDP_TX:
+ rcu_read_unlock();
+ goto xdp_xmit;
+ case XDP_DROP:
+ default:
+ goto err_xdp;
+ }
+ }
+ rcu_read_unlock();
+
+ skb = page_to_skb(vi, rq, page, 0, len, PAGE_SIZE);
if (unlikely(!skb))
goto err;
return skb;
+err_xdp:
+ rcu_read_unlock();
err:
dev->stats.rx_dropped++;
give_pages(rq, page);
+xdp_xmit:
+ return NULL;
+}
+
+/* The conditions to enable XDP should preclude the underlying device from
+ * sending packets across multiple buffers (num_buf > 1). However per spec
+ * it does not appear to be illegal to do so but rather just against convention.
+ * So in order to avoid making a system unresponsive the packets are pushed
+ * into a page and the XDP program is run. This will be extremely slow and we
+ * push a warning to the user to fix this as soon as possible. Fixing this may
+ * require resolving the underlying hardware to determine why multiple buffers
+ * are being received or simply loading the XDP program in the ingress stack
+ * after the skb is built because there is no advantage to running it here
+ * anymore.
+ */
+static struct page *xdp_linearize_page(struct receive_queue *rq,
+ u16 num_buf,
+ struct page *p,
+ int offset,
+ unsigned int *len)
+{
+ struct page *page = alloc_page(GFP_ATOMIC);
+ unsigned int page_off = 0;
+
+ if (!page)
+ return NULL;
+
+ memcpy(page_address(page) + page_off, page_address(p) + offset, *len);
+ page_off += *len;
+
+ while (--num_buf) {
+ unsigned int buflen;
+ unsigned long ctx;
+ void *buf;
+ int off;
+
+ ctx = (unsigned long)virtqueue_get_buf(rq->vq, &buflen);
+ if (unlikely(!ctx))
+ goto err_buf;
+
+ /* guard against a misconfigured or uncooperative backend that
+ * is sending packet larger than the MTU.
+ */
+ if ((page_off + buflen) > PAGE_SIZE)
+ goto err_buf;
+
+ buf = mergeable_ctx_to_buf_address(ctx);
+ p = virt_to_head_page(buf);
+ off = buf - page_address(p);
+
+ memcpy(page_address(page) + page_off,
+ page_address(p) + off, buflen);
+ page_off += buflen;
+ }
+
+ *len = page_off;
+ return page;
+err_buf:
+ __free_pages(page, 0);
return NULL;
}
@@ -365,11 +540,67 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
u16 num_buf = virtio16_to_cpu(vi->vdev, hdr->num_buffers);
struct page *page = virt_to_head_page(buf);
int offset = buf - page_address(page);
- unsigned int truesize = max(len, mergeable_ctx_to_buf_truesize(ctx));
+ struct sk_buff *head_skb, *curr_skb;
+ struct bpf_prog *xdp_prog;
+ unsigned int truesize;
+
+ head_skb = NULL;
+
+ rcu_read_lock();
+ xdp_prog = rcu_dereference(rq->xdp_prog);
+ if (xdp_prog) {
+ struct page *xdp_page;
+ u32 act;
+
+ /* No known backend devices should send packets with
+ * more than a single buffer when XDP conditions are
+ * met. However it is not strictly illegal so the case
+ * is handled as an exception and a warning is thrown.
+ */
+ if (unlikely(num_buf > 1)) {
+ bpf_warn_invalid_xdp_buffer();
+
+ /* linearize data for XDP */
+ xdp_page = xdp_linearize_page(rq, num_buf,
+ page, offset, &len);
+ if (!xdp_page)
+ goto err_xdp;
+ offset = 0;
+ } else {
+ xdp_page = page;
+ }
+
+ /* Transient failure which in theory could occur if
+ * in-flight packets from before XDP was enabled reach
+ * the receive path after XDP is loaded. In practice I
+ * was not able to create this condition.
+ */
+ if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags))
+ goto err_xdp;
+
+ act = do_xdp_prog(vi, rq, xdp_prog, page, offset, len);
+ switch (act) {
+ case XDP_PASS:
+ if (unlikely(xdp_page != page))
+ __free_pages(xdp_page, 0);
+ break;
+ case XDP_TX:
+ if (unlikely(xdp_page != page))
+ goto err_xdp;
+ rcu_read_unlock();
+ goto xdp_xmit;
+ case XDP_DROP:
+ default:
+ if (unlikely(xdp_page != page))
+ __free_pages(xdp_page, 0);
+ goto err_xdp;
+ }
+ }
+ rcu_read_unlock();
- struct sk_buff *head_skb = page_to_skb(vi, rq, page, offset, len,
- truesize);
- struct sk_buff *curr_skb = head_skb;
+ truesize = max(len, mergeable_ctx_to_buf_truesize(ctx));
+ head_skb = page_to_skb(vi, rq, page, offset, len, truesize);
+ curr_skb = head_skb;
if (unlikely(!curr_skb))
goto err_skb;
@@ -423,6 +654,8 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
ewma_pkt_len_add(&rq->mrg_avg_pkt_len, head_skb->len);
return head_skb;
+err_xdp:
+ rcu_read_unlock();
err_skb:
put_page(page);
while (--num_buf) {
@@ -439,6 +672,7 @@ err_skb:
err_buf:
dev->stats.rx_dropped++;
dev_kfree_skb(head_skb);
+xdp_xmit:
return NULL;
}
@@ -1337,6 +1571,13 @@ static int virtnet_set_channels(struct net_device *dev,
if (queue_pairs > vi->max_queue_pairs || queue_pairs == 0)
return -EINVAL;
+ /* For now we don't support modifying channels while XDP is loaded
+ * also when XDP is loaded all RX queues have XDP programs so we only
+ * need to check a single RX queue.
+ */
+ if (vi->rq[0].xdp_prog)
+ return -EINVAL;
+
get_online_cpus();
err = virtnet_set_queues(vi, queue_pairs);
if (!err) {
@@ -1428,6 +1669,93 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
.set_settings = virtnet_set_settings,
};
+static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog)
+{
+ unsigned long int max_sz = PAGE_SIZE - sizeof(struct padded_vnet_hdr);
+ struct virtnet_info *vi = netdev_priv(dev);
+ struct bpf_prog *old_prog;
+ u16 xdp_qp = 0, curr_qp;
+ int i, err;
+
+ if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO4) ||
+ virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO6)) {
+ netdev_warn(dev, "can't set XDP while host is implementing LRO, disable LRO first\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (vi->mergeable_rx_bufs && !vi->any_header_sg) {
+ netdev_warn(dev, "XDP expects header/data in single page, any_header_sg required\n");
+ return -EINVAL;
+ }
+
+ if (dev->mtu > max_sz) {
+ netdev_warn(dev, "XDP requires MTU less than %lu\n", max_sz);
+ return -EINVAL;
+ }
+
+ curr_qp = vi->curr_queue_pairs - vi->xdp_queue_pairs;
+ if (prog)
+ xdp_qp = nr_cpu_ids;
+
+ /* XDP requires extra queues for XDP_TX */
+ if (curr_qp + xdp_qp > vi->max_queue_pairs) {
+ netdev_warn(dev, "request %i queues but max is %i\n",
+ curr_qp + xdp_qp, vi->max_queue_pairs);
+ return -ENOMEM;
+ }
+
+ err = virtnet_set_queues(vi, curr_qp + xdp_qp);
+ if (err) {
+ dev_warn(&dev->dev, "XDP Device queue allocation failure.\n");
+ return err;
+ }
+
+ if (prog) {
+ prog = bpf_prog_add(prog, vi->max_queue_pairs - 1);
+ if (IS_ERR(prog)) {
+ virtnet_set_queues(vi, curr_qp);
+ return PTR_ERR(prog);
+ }
+ }
+
+ vi->xdp_queue_pairs = xdp_qp;
+ netif_set_real_num_rx_queues(dev, curr_qp + xdp_qp);
+
+ for (i = 0; i < vi->max_queue_pairs; i++) {
+ old_prog = rtnl_dereference(vi->rq[i].xdp_prog);
+ rcu_assign_pointer(vi->rq[i].xdp_prog, prog);
+ if (old_prog)
+ bpf_prog_put(old_prog);
+ }
+
+ return 0;
+}
+
+static bool virtnet_xdp_query(struct net_device *dev)
+{
+ struct virtnet_info *vi = netdev_priv(dev);
+ int i;
+
+ for (i = 0; i < vi->max_queue_pairs; i++) {
+ if (vi->rq[i].xdp_prog)
+ return true;
+ }
+ return false;
+}
+
+static int virtnet_xdp(struct net_device *dev, struct netdev_xdp *xdp)
+{
+ switch (xdp->command) {
+ case XDP_SETUP_PROG:
+ return virtnet_xdp_set(dev, xdp->prog);
+ case XDP_QUERY_PROG:
+ xdp->prog_attached = virtnet_xdp_query(dev);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
static const struct net_device_ops virtnet_netdev = {
.ndo_open = virtnet_open,
.ndo_stop = virtnet_close,
@@ -1444,6 +1772,7 @@ static const struct net_device_ops virtnet_netdev = {
#ifdef CONFIG_NET_RX_BUSY_POLL
.ndo_busy_poll = virtnet_busy_poll,
#endif
+ .ndo_xdp = virtnet_xdp,
};
static void virtnet_config_changed_work(struct work_struct *work)
@@ -1505,12 +1834,20 @@ static void virtnet_free_queues(struct virtnet_info *vi)
static void free_receive_bufs(struct virtnet_info *vi)
{
+ struct bpf_prog *old_prog;
int i;
+ rtnl_lock();
for (i = 0; i < vi->max_queue_pairs; i++) {
while (vi->rq[i].pages)
__free_pages(get_a_page(&vi->rq[i], GFP_KERNEL), 0);
+
+ old_prog = rtnl_dereference(vi->rq[i].xdp_prog);
+ RCU_INIT_POINTER(vi->rq[i].xdp_prog, NULL);
+ if (old_prog)
+ bpf_prog_put(old_prog);
}
+ rtnl_unlock();
}
static void free_receive_page_frags(struct virtnet_info *vi)
@@ -1521,6 +1858,16 @@ static void free_receive_page_frags(struct virtnet_info *vi)
put_page(vi->rq[i].alloc_frag.page);
}
+static bool is_xdp_queue(struct virtnet_info *vi, int q)
+{
+ if (q < (vi->curr_queue_pairs - vi->xdp_queue_pairs))
+ return false;
+ else if (q < vi->curr_queue_pairs)
+ return true;
+ else
+ return false;
+}
+
static void free_unused_bufs(struct virtnet_info *vi)
{
void *buf;
@@ -1528,8 +1875,12 @@ static void free_unused_bufs(struct virtnet_info *vi)
for (i = 0; i < vi->max_queue_pairs; i++) {
struct virtqueue *vq = vi->sq[i].vq;
- while ((buf = virtqueue_detach_unused_buf(vq)) != NULL)
- dev_kfree_skb(buf);
+ while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) {
+ if (!is_xdp_queue(vi, i))
+ dev_kfree_skb(buf);
+ else
+ put_page(virt_to_head_page(buf));
+ }
}
for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -1930,7 +2281,9 @@ static int virtnet_probe(struct virtio_device *vdev)
goto free_unregister_netdev;
}
- virtnet_set_affinity(vi);
+ rtnl_lock();
+ virtnet_set_queues(vi, vi->curr_queue_pairs);
+ rtnl_unlock();
/* Assume link up if device can't report link status,
otherwise get link status from config. */
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 3bca24651dc0..7532646c3b7b 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -366,6 +366,8 @@ static int vrf_finish_output6(struct net *net, struct sock *sk,
struct in6_addr *nexthop;
int ret;
+ nf_reset(skb);
+
skb->protocol = htons(ETH_P_IPV6);
skb->dev = dev;
@@ -547,6 +549,8 @@ static int vrf_finish_output(struct net *net, struct sock *sk, struct sk_buff *s
u32 nexthop;
int ret = -EINVAL;
+ nf_reset(skb);
+
/* Be paranoid, rather than too clever. */
if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {
struct sk_buff *skb2;
@@ -849,8 +853,6 @@ static struct sk_buff *vrf_rcv_nfhook(u8 pf, unsigned int hook,
{
struct net *net = dev_net(dev);
- nf_reset(skb);
-
if (NF_HOOK(pf, hook, net, NULL, skb, dev, NULL, vrf_rcv_finish) < 0)
skb = NULL; /* kfree_skb(skb) handled by nf code */
diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c
index 5920c996fcdf..ff2e4a5654c7 100644
--- a/drivers/net/wan/lmc/lmc_media.c
+++ b/drivers/net/wan/lmc/lmc_media.c
@@ -95,62 +95,63 @@ static inline void write_av9110_bit (lmc_softc_t *, int);
static void write_av9110(lmc_softc_t *, u32, u32, u32, u32, u32);
lmc_media_t lmc_ds3_media = {
- lmc_ds3_init, /* special media init stuff */
- lmc_ds3_default, /* reset to default state */
- lmc_ds3_set_status, /* reset status to state provided */
- lmc_dummy_set_1, /* set clock source */
- lmc_dummy_set2_1, /* set line speed */
- lmc_ds3_set_100ft, /* set cable length */
- lmc_ds3_set_scram, /* set scrambler */
- lmc_ds3_get_link_status, /* get link status */
- lmc_dummy_set_1, /* set link status */
- lmc_ds3_set_crc_length, /* set CRC length */
- lmc_dummy_set_1, /* set T1 or E1 circuit type */
- lmc_ds3_watchdog
+ .init = lmc_ds3_init, /* special media init stuff */
+ .defaults = lmc_ds3_default, /* reset to default state */
+ .set_status = lmc_ds3_set_status, /* reset status to state provided */
+ .set_clock_source = lmc_dummy_set_1, /* set clock source */
+ .set_speed = lmc_dummy_set2_1, /* set line speed */
+ .set_cable_length = lmc_ds3_set_100ft, /* set cable length */
+ .set_scrambler = lmc_ds3_set_scram, /* set scrambler */
+ .get_link_status = lmc_ds3_get_link_status, /* get link status */
+ .set_link_status = lmc_dummy_set_1, /* set link status */
+ .set_crc_length = lmc_ds3_set_crc_length, /* set CRC length */
+ .set_circuit_type = lmc_dummy_set_1, /* set T1 or E1 circuit type */
+ .watchdog = lmc_ds3_watchdog
};
lmc_media_t lmc_hssi_media = {
- lmc_hssi_init, /* special media init stuff */
- lmc_hssi_default, /* reset to default state */
- lmc_hssi_set_status, /* reset status to state provided */
- lmc_hssi_set_clock, /* set clock source */
- lmc_dummy_set2_1, /* set line speed */
- lmc_dummy_set_1, /* set cable length */
- lmc_dummy_set_1, /* set scrambler */
- lmc_hssi_get_link_status, /* get link status */
- lmc_hssi_set_link_status, /* set link status */
- lmc_hssi_set_crc_length, /* set CRC length */
- lmc_dummy_set_1, /* set T1 or E1 circuit type */
- lmc_hssi_watchdog
+ .init = lmc_hssi_init, /* special media init stuff */
+ .defaults = lmc_hssi_default, /* reset to default state */
+ .set_status = lmc_hssi_set_status, /* reset status to state provided */
+ .set_clock_source = lmc_hssi_set_clock, /* set clock source */
+ .set_speed = lmc_dummy_set2_1, /* set line speed */
+ .set_cable_length = lmc_dummy_set_1, /* set cable length */
+ .set_scrambler = lmc_dummy_set_1, /* set scrambler */
+ .get_link_status = lmc_hssi_get_link_status, /* get link status */
+ .set_link_status = lmc_hssi_set_link_status, /* set link status */
+ .set_crc_length = lmc_hssi_set_crc_length, /* set CRC length */
+ .set_circuit_type = lmc_dummy_set_1, /* set T1 or E1 circuit type */
+ .watchdog = lmc_hssi_watchdog
};
-lmc_media_t lmc_ssi_media = { lmc_ssi_init, /* special media init stuff */
- lmc_ssi_default, /* reset to default state */
- lmc_ssi_set_status, /* reset status to state provided */
- lmc_ssi_set_clock, /* set clock source */
- lmc_ssi_set_speed, /* set line speed */
- lmc_dummy_set_1, /* set cable length */
- lmc_dummy_set_1, /* set scrambler */
- lmc_ssi_get_link_status, /* get link status */
- lmc_ssi_set_link_status, /* set link status */
- lmc_ssi_set_crc_length, /* set CRC length */
- lmc_dummy_set_1, /* set T1 or E1 circuit type */
- lmc_ssi_watchdog
+lmc_media_t lmc_ssi_media = {
+ .init = lmc_ssi_init, /* special media init stuff */
+ .defaults = lmc_ssi_default, /* reset to default state */
+ .set_status = lmc_ssi_set_status, /* reset status to state provided */
+ .set_clock_source = lmc_ssi_set_clock, /* set clock source */
+ .set_speed = lmc_ssi_set_speed, /* set line speed */
+ .set_cable_length = lmc_dummy_set_1, /* set cable length */
+ .set_scrambler = lmc_dummy_set_1, /* set scrambler */
+ .get_link_status = lmc_ssi_get_link_status, /* get link status */
+ .set_link_status = lmc_ssi_set_link_status, /* set link status */
+ .set_crc_length = lmc_ssi_set_crc_length, /* set CRC length */
+ .set_circuit_type = lmc_dummy_set_1, /* set T1 or E1 circuit type */
+ .watchdog = lmc_ssi_watchdog
};
lmc_media_t lmc_t1_media = {
- lmc_t1_init, /* special media init stuff */
- lmc_t1_default, /* reset to default state */
- lmc_t1_set_status, /* reset status to state provided */
- lmc_t1_set_clock, /* set clock source */
- lmc_dummy_set2_1, /* set line speed */
- lmc_dummy_set_1, /* set cable length */
- lmc_dummy_set_1, /* set scrambler */
- lmc_t1_get_link_status, /* get link status */
- lmc_dummy_set_1, /* set link status */
- lmc_t1_set_crc_length, /* set CRC length */
- lmc_t1_set_circuit_type, /* set T1 or E1 circuit type */
- lmc_t1_watchdog
+ .init = lmc_t1_init, /* special media init stuff */
+ .defaults = lmc_t1_default, /* reset to default state */
+ .set_status = lmc_t1_set_status, /* reset status to state provided */
+ .set_clock_source = lmc_t1_set_clock, /* set clock source */
+ .set_speed = lmc_dummy_set2_1, /* set line speed */
+ .set_cable_length = lmc_dummy_set_1, /* set cable length */
+ .set_scrambler = lmc_dummy_set_1, /* set scrambler */
+ .get_link_status = lmc_t1_get_link_status, /* get link status */
+ .set_link_status = lmc_dummy_set_1, /* set link status */
+ .set_crc_length = lmc_t1_set_crc_length, /* set CRC length */
+ .set_circuit_type = lmc_t1_set_circuit_type, /* set T1 or E1 circuit type */
+ .watchdog = lmc_t1_watchdog
};
static void
diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c
index d5dc80c48b4c..b3323c0697f6 100644
--- a/drivers/nvdimm/claim.c
+++ b/drivers/nvdimm/claim.c
@@ -22,9 +22,8 @@ void __nd_detach_ndns(struct device *dev, struct nd_namespace_common **_ndns)
{
struct nd_namespace_common *ndns = *_ndns;
- dev_WARN_ONCE(dev, !mutex_is_locked(&ndns->dev.mutex)
- || ndns->claim != dev,
- "%s: invalid claim\n", __func__);
+ lockdep_assert_held(&ndns->dev.mutex);
+ dev_WARN_ONCE(dev, ndns->claim != dev, "%s: invalid claim\n", __func__);
ndns->claim = NULL;
*_ndns = NULL;
put_device(&ndns->dev);
@@ -49,9 +48,8 @@ bool __nd_attach_ndns(struct device *dev, struct nd_namespace_common *attach,
{
if (attach->claim)
return false;
- dev_WARN_ONCE(dev, !mutex_is_locked(&attach->dev.mutex)
- || *_ndns,
- "%s: invalid claim\n", __func__);
+ lockdep_assert_held(&attach->dev.mutex);
+ dev_WARN_ONCE(dev, *_ndns, "%s: invalid claim\n", __func__);
attach->claim = dev;
*_ndns = attach;
get_device(&attach->dev);
@@ -226,6 +224,12 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
resource_size_t offset, void *buf, size_t size, int rw)
{
struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+ unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512);
+ sector_t sector = offset >> 9;
+ int rc = 0;
+
+ if (unlikely(!size))
+ return 0;
if (unlikely(offset + size > nsio->size)) {
dev_WARN_ONCE(&ndns->dev, 1, "request out of range\n");
@@ -233,17 +237,31 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
}
if (rw == READ) {
- unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512);
-
- if (unlikely(is_bad_pmem(&nsio->bb, offset / 512, sz_align)))
+ if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align)))
return -EIO;
return memcpy_from_pmem(buf, nsio->addr + offset, size);
- } else {
- memcpy_to_pmem(nsio->addr + offset, buf, size);
- nvdimm_flush(to_nd_region(ndns->dev.parent));
}
- return 0;
+ if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) {
+ if (IS_ALIGNED(offset, 512) && IS_ALIGNED(size, 512)) {
+ long cleared;
+
+ cleared = nvdimm_clear_poison(&ndns->dev, offset, size);
+ if (cleared < size)
+ rc = -EIO;
+ if (cleared > 0 && cleared / 512) {
+ cleared /= 512;
+ badblocks_clear(&nsio->bb, sector, cleared);
+ }
+ invalidate_pmem(nsio->addr + offset, size);
+ } else
+ rc = -EIO;
+ }
+
+ memcpy_to_pmem(nsio->addr + offset, buf, size);
+ nvdimm_flush(to_nd_region(ndns->dev.parent));
+
+ return rc;
}
int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio)
@@ -253,7 +271,7 @@ int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio)
nsio->size = resource_size(res);
if (!devm_request_mem_region(dev, res->start, resource_size(res),
- dev_name(dev))) {
+ dev_name(&ndns->dev))) {
dev_warn(dev, "could not reserve region %pR\n", res);
return -EBUSY;
}
diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c
index 7ceba08774b6..9303cfeb8bee 100644
--- a/drivers/nvdimm/core.c
+++ b/drivers/nvdimm/core.c
@@ -317,35 +317,6 @@ ssize_t nd_sector_size_store(struct device *dev, const char *buf,
}
}
-void __nd_iostat_start(struct bio *bio, unsigned long *start)
-{
- struct gendisk *disk = bio->bi_bdev->bd_disk;
- const int rw = bio_data_dir(bio);
- int cpu = part_stat_lock();
-
- *start = jiffies;
- part_round_stats(cpu, &disk->part0);
- part_stat_inc(cpu, &disk->part0, ios[rw]);
- part_stat_add(cpu, &disk->part0, sectors[rw], bio_sectors(bio));
- part_inc_in_flight(&disk->part0, rw);
- part_stat_unlock();
-}
-EXPORT_SYMBOL(__nd_iostat_start);
-
-void nd_iostat_end(struct bio *bio, unsigned long start)
-{
- struct gendisk *disk = bio->bi_bdev->bd_disk;
- unsigned long duration = jiffies - start;
- const int rw = bio_data_dir(bio);
- int cpu = part_stat_lock();
-
- part_stat_add(cpu, &disk->part0, ticks[rw], duration);
- part_round_stats(cpu, &disk->part0);
- part_dec_in_flight(&disk->part0, rw);
- part_stat_unlock();
-}
-EXPORT_SYMBOL(nd_iostat_end);
-
static ssize_t commands_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c
index 619834e144d1..ee0b412827bf 100644
--- a/drivers/nvdimm/dimm.c
+++ b/drivers/nvdimm/dimm.c
@@ -64,6 +64,8 @@ static int nvdimm_probe(struct device *dev)
nd_label_copy(ndd, to_next_namespace_index(ndd),
to_current_namespace_index(ndd));
rc = nd_label_reserve_dpa(ndd);
+ if (ndd->ns_current >= 0)
+ nvdimm_set_aliasing(dev);
nvdimm_bus_unlock(dev);
if (rc)
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
index d614493ad5ac..0eedc49e0d47 100644
--- a/drivers/nvdimm/dimm_devs.c
+++ b/drivers/nvdimm/dimm_devs.c
@@ -184,6 +184,13 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
return rc;
}
+void nvdimm_set_aliasing(struct device *dev)
+{
+ struct nvdimm *nvdimm = to_nvdimm(dev);
+
+ nvdimm->flags |= NDD_ALIASING;
+}
+
static void nvdimm_release(struct device *dev)
{
struct nvdimm *nvdimm = to_nvdimm(dev);
diff --git a/drivers/nvdimm/e820.c b/drivers/nvdimm/e820.c
index 11ea90120542..6f9a6ffd7cde 100644
--- a/drivers/nvdimm/e820.c
+++ b/drivers/nvdimm/e820.c
@@ -84,18 +84,8 @@ static struct platform_driver e820_pmem_driver = {
},
};
-static __init int e820_pmem_init(void)
-{
- return platform_driver_register(&e820_pmem_driver);
-}
-
-static __exit void e820_pmem_exit(void)
-{
- platform_driver_unregister(&e820_pmem_driver);
-}
+module_platform_driver(e820_pmem_driver);
MODULE_ALIAS("platform:e820_pmem*");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Intel Corporation");
-module_init(e820_pmem_init);
-module_exit(e820_pmem_exit);
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index fac7cabe8f56..dd615345699f 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -938,7 +938,7 @@ int nd_pmem_namespace_label_update(struct nd_region *nd_region,
}
for_each_dpa_resource(ndd, res)
- if (strncmp(res->name, "pmem", 3) == 0)
+ if (strncmp(res->name, "pmem", 4) == 0)
count++;
WARN_ON_ONCE(!count);
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index abe5c6bc756c..6307088b375f 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -1132,7 +1132,7 @@ static ssize_t size_show(struct device *dev,
return sprintf(buf, "%llu\n", (unsigned long long)
nvdimm_namespace_capacity(to_ndns(dev)));
}
-static DEVICE_ATTR(size, S_IRUGO, size_show, size_store);
+static DEVICE_ATTR(size, 0444, size_show, size_store);
static u8 *namespace_to_uuid(struct device *dev)
{
@@ -1456,7 +1456,7 @@ static umode_t namespace_visible(struct kobject *kobj,
if (is_namespace_pmem(dev) || is_namespace_blk(dev)) {
if (a == &dev_attr_size.attr)
- return S_IWUSR | S_IRUGO;
+ return 0644;
if (is_namespace_pmem(dev) && a == &dev_attr_sector_size.attr)
return 0;
@@ -1653,7 +1653,7 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id)
u64 hw_start, hw_end, pmem_start, pmem_end;
struct nd_label_ent *label_ent;
- WARN_ON(!mutex_is_locked(&nd_mapping->lock));
+ lockdep_assert_held(&nd_mapping->lock);
list_for_each_entry(label_ent, &nd_mapping->labels, list) {
nd_label = label_ent->label;
if (!nd_label)
@@ -1997,7 +1997,7 @@ struct device *create_namespace_blk(struct nd_region *nd_region,
struct nd_mapping *nd_mapping = &nd_region->mapping[0];
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
struct nd_namespace_blk *nsblk;
- char *name[NSLABEL_NAME_LEN];
+ char name[NSLABEL_NAME_LEN];
struct device *dev = NULL;
struct resource *res;
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index d3b2fca8deec..35dd75057e16 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -238,6 +238,7 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
void *buf, size_t len);
long nvdimm_clear_poison(struct device *dev, phys_addr_t phys,
unsigned int len);
+void nvdimm_set_aliasing(struct device *dev);
struct nd_btt *to_nd_btt(struct device *dev);
struct nd_gen_sb {
@@ -377,10 +378,17 @@ static inline bool nd_iostat_start(struct bio *bio, unsigned long *start)
if (!blk_queue_io_stat(disk->queue))
return false;
- __nd_iostat_start(bio, start);
+ *start = jiffies;
+ generic_start_io_acct(bio_data_dir(bio),
+ bio_sectors(bio), &disk->part0);
return true;
}
-void nd_iostat_end(struct bio *bio, unsigned long start);
+static inline void nd_iostat_end(struct bio *bio, unsigned long start)
+{
+ struct gendisk *disk = bio->bi_bdev->bd_disk;
+
+ generic_end_io_acct(bio_data_dir(bio), &disk->part0, start);
+}
static inline bool is_bad_pmem(struct badblocks *bb, sector_t sector,
unsigned int len)
{
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index cea8350fbc7e..a2ac9e641aa9 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -108,7 +108,7 @@ static ssize_t align_show(struct device *dev,
{
struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
- return sprintf(buf, "%lx\n", nd_pfn->align);
+ return sprintf(buf, "%ld\n", nd_pfn->align);
}
static ssize_t __align_store(struct nd_pfn *nd_pfn, const char *buf)
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 24618431a14b..7282d7495bf1 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -53,21 +53,24 @@ static int pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
struct device *dev = to_dev(pmem);
sector_t sector;
long cleared;
+ int rc = 0;
sector = (offset - pmem->data_offset) / 512;
- cleared = nvdimm_clear_poison(dev, pmem->phys_addr + offset, len);
+ cleared = nvdimm_clear_poison(dev, pmem->phys_addr + offset, len);
+ if (cleared < len)
+ rc = -EIO;
if (cleared > 0 && cleared / 512) {
- dev_dbg(dev, "%s: %#llx clear %ld sector%s\n",
- __func__, (unsigned long long) sector,
- cleared / 512, cleared / 512 > 1 ? "s" : "");
- badblocks_clear(&pmem->bb, sector, cleared / 512);
- } else {
- return -EIO;
+ cleared /= 512;
+ dev_dbg(dev, "%s: %#llx clear %ld sector%s\n", __func__,
+ (unsigned long long) sector, cleared,
+ cleared > 1 ? "s" : "");
+ badblocks_clear(&pmem->bb, sector, cleared);
}
invalidate_pmem(pmem->virt_addr + offset, len);
- return 0;
+
+ return rc;
}
static void write_pmem(void *pmem_addr, struct page *page,
@@ -270,7 +273,7 @@ static int pmem_attach_disk(struct device *dev,
dev_warn(dev, "unable to guarantee persistence of writes\n");
if (!devm_request_mem_region(dev, res->start, resource_size(res),
- dev_name(dev))) {
+ dev_name(&ndns->dev))) {
dev_warn(dev, "could not reserve region %pR\n", res);
return -EBUSY;
}
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index 6af5e629140c..7cd705f3247c 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -509,7 +509,7 @@ void nd_mapping_free_labels(struct nd_mapping *nd_mapping)
{
struct nd_label_ent *label_ent, *e;
- WARN_ON(!mutex_is_locked(&nd_mapping->lock));
+ lockdep_assert_held(&nd_mapping->lock);
list_for_each_entry_safe(label_ent, e, &nd_mapping->labels, list) {
list_del(&label_ent->list);
kfree(label_ent);
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index 82f7000a285d..642478d35e99 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -206,7 +206,7 @@ void sync_stop(void)
* because we cannot reach this code without at least one
* dcookie user still being registered (namely, the reader
* of the event buffer). */
-static inline unsigned long fast_get_dcookie(struct path *path)
+static inline unsigned long fast_get_dcookie(const struct path *path)
{
unsigned long cookie;
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 185376901d9c..5fe8be089b8b 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -363,6 +363,18 @@ config IDEAPAD_LAPTOP
This is a driver for Lenovo IdeaPad netbooks contains drivers for
rfkill switch, hotkey, fan control and backlight control.
+config SURFACE3_WMI
+ tristate "Surface 3 WMI Driver"
+ depends on ACPI_WMI
+ depends on DMI
+ depends on INPUT
+ depends on SPI
+ ---help---
+ Say Y here if you have a Surface 3.
+
+ To compile this driver as a module, choose M here: the module will
+ be called surface3-wmi.
+
config THINKPAD_ACPI
tristate "ThinkPad ACPI Laptop Extras"
depends on ACPI
@@ -1005,12 +1017,27 @@ config INTEL_PMC_IPC
The PMC is an ARC processor which defines IPC commands for communication
with other entities in the CPU.
+config INTEL_BXTWC_PMIC_TMU
+ tristate "Intel BXT Whiskey Cove TMU Driver"
+ depends on REGMAP
+ depends on INTEL_SOC_PMIC && INTEL_PMC_IPC
+ ---help---
+ Select this driver to use Intel BXT Whiskey Cove PMIC TMU feature.
+ This driver enables the alarm wakeup functionality in the TMU unit
+ of Whiskey Cove PMIC.
+
config SURFACE_PRO3_BUTTON
tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet"
depends on ACPI && INPUT
---help---
This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3/4 tablet.
+config SURFACE_3_BUTTON
+ tristate "Power/home/volume buttons driver for Microsoft Surface 3 tablet"
+ depends on ACPI && KEYBOARD_GPIO
+ ---help---
+ This driver handles the power/home/volume buttons on the Microsoft Surface 3 tablet.
+
config INTEL_PUNIT_IPC
tristate "Intel P-Unit IPC Driver"
---help---
@@ -1028,10 +1055,21 @@ config INTEL_TELEMETRY
directly via debugfs files. Various tools may use
this interface for SoC state monitoring.
+config MLX_PLATFORM
+ tristate "Mellanox Technologies platform support"
+ depends on X86_64
+ ---help---
+ This option enables system support for the Mellanox Technologies
+ platform. The Mellanox systems provide data center networking
+ solutions based on Virtual Protocol Interconnect (VPI) technology
+ enable seamless connectivity to 56/100Gb/s InfiniBand or 10/40/56GbE
+ connection.
+
+ If you have a Mellanox system, say Y or M here.
+
config MLX_CPLD_PLATFORM
tristate "Mellanox platform hotplug driver support"
default n
- depends on MLX_PLATFORM
select HWMON
select I2C
---help---
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 1f06b6339cf7..d4111f0f8a78 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
obj-$(CONFIG_ACPI_WMI) += wmi.o
obj-$(CONFIG_MSI_WMI) += msi-wmi.o
+obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o
obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
# toshiba_acpi must link after wmi to ensure that wmi devices are found
@@ -66,9 +67,12 @@ obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o
obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o
obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
+obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o
obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o
+obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU) += intel_bxtwc_tmu.o
obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \
intel_telemetry_pltdrv.o \
intel_telemetry_debugfs.o
obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o
+obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index a7614fc542b5..410741acb3c9 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -871,6 +871,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
},
},
{
+ .ident = "Lenovo ideapad Y700-15ACZ",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ACZ"),
+ },
+ },
+ {
.ident = "Lenovo ideapad Y700-15ISK",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
diff --git a/drivers/platform/x86/intel_bxtwc_tmu.c b/drivers/platform/x86/intel_bxtwc_tmu.c
new file mode 100644
index 000000000000..e202abd5b0df
--- /dev/null
+++ b/drivers/platform/x86/intel_bxtwc_tmu.c
@@ -0,0 +1,162 @@
+/*
+ * intel_bxtwc_tmu.c - Intel BXT Whiskey Cove PMIC TMU driver
+ *
+ * Copyright (C) 2016 Intel Corporation. All rights reserved.
+ *
+ * This driver adds TMU (Time Management Unit) support for Intel BXT platform.
+ * It enables the alarm wake-up functionality in the TMU unit of Whiskey Cove
+ * PMIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/intel_soc_pmic.h>
+
+#define BXTWC_TMUIRQ 0x4fb6
+#define BXTWC_MIRQLVL1 0x4e0e
+#define BXTWC_MTMUIRQ_REG 0x4fb7
+#define BXTWC_MIRQLVL1_MTMU BIT(1)
+#define BXTWC_TMU_WK_ALRM BIT(1)
+#define BXTWC_TMU_SYS_ALRM BIT(2)
+#define BXTWC_TMU_ALRM_MASK (BXTWC_TMU_WK_ALRM | BXTWC_TMU_SYS_ALRM)
+#define BXTWC_TMU_ALRM_IRQ (BXTWC_TMU_WK_ALRM | BXTWC_TMU_SYS_ALRM)
+
+struct wcove_tmu {
+ int irq;
+ struct device *dev;
+ struct regmap *regmap;
+};
+
+static irqreturn_t bxt_wcove_tmu_irq_handler(int irq, void *data)
+{
+ struct wcove_tmu *wctmu = data;
+ unsigned int tmu_irq;
+
+ /* Read TMU interrupt reg */
+ regmap_read(wctmu->regmap, BXTWC_TMUIRQ, &tmu_irq);
+ if (tmu_irq & BXTWC_TMU_ALRM_IRQ) {
+ /* clear TMU irq */
+ regmap_write(wctmu->regmap, BXTWC_TMUIRQ, tmu_irq);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+static int bxt_wcove_tmu_probe(struct platform_device *pdev)
+{
+ struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
+ struct regmap_irq_chip_data *regmap_irq_chip;
+ struct wcove_tmu *wctmu;
+ int ret, virq, irq;
+
+ wctmu = devm_kzalloc(&pdev->dev, sizeof(*wctmu), GFP_KERNEL);
+ if (!wctmu)
+ return -ENOMEM;
+
+ wctmu->dev = &pdev->dev;
+ wctmu->regmap = pmic->regmap;
+
+ irq = platform_get_irq(pdev, 0);
+
+ if (irq < 0) {
+ dev_err(&pdev->dev, "invalid irq %d\n", irq);
+ return irq;
+ }
+
+ regmap_irq_chip = pmic->irq_chip_data_tmu;
+ virq = regmap_irq_get_virq(regmap_irq_chip, irq);
+ if (virq < 0) {
+ dev_err(&pdev->dev,
+ "failed to get virtual interrupt=%d\n", irq);
+ return virq;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, virq,
+ NULL, bxt_wcove_tmu_irq_handler,
+ IRQF_ONESHOT, "bxt_wcove_tmu", wctmu);
+ if (ret) {
+ dev_err(&pdev->dev, "request irq failed: %d,virq: %d\n",
+ ret, virq);
+ return ret;
+ }
+ wctmu->irq = virq;
+
+ /* Enable TMU interrupts */
+ regmap_update_bits(wctmu->regmap, BXTWC_MIRQLVL1,
+ BXTWC_MIRQLVL1_MTMU, 0);
+
+ /* Unmask TMU second level Wake & System alarm */
+ regmap_update_bits(wctmu->regmap, BXTWC_MTMUIRQ_REG,
+ BXTWC_TMU_ALRM_MASK, 0);
+
+ platform_set_drvdata(pdev, wctmu);
+ return 0;
+}
+
+static int bxt_wcove_tmu_remove(struct platform_device *pdev)
+{
+ struct wcove_tmu *wctmu = platform_get_drvdata(pdev);
+ unsigned int val;
+
+ /* Mask TMU interrupts */
+ regmap_read(wctmu->regmap, BXTWC_MIRQLVL1, &val);
+ regmap_write(wctmu->regmap, BXTWC_MIRQLVL1,
+ val | BXTWC_MIRQLVL1_MTMU);
+ regmap_read(wctmu->regmap, BXTWC_MTMUIRQ_REG, &val);
+ regmap_write(wctmu->regmap, BXTWC_MTMUIRQ_REG,
+ val | BXTWC_TMU_ALRM_MASK);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int bxtwc_tmu_suspend(struct device *dev)
+{
+ struct wcove_tmu *wctmu = dev_get_drvdata(dev);
+
+ enable_irq_wake(wctmu->irq);
+ return 0;
+}
+
+static int bxtwc_tmu_resume(struct device *dev)
+{
+ struct wcove_tmu *wctmu = dev_get_drvdata(dev);
+
+ disable_irq_wake(wctmu->irq);
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(bxtwc_tmu_pm_ops, bxtwc_tmu_suspend, bxtwc_tmu_resume);
+
+static const struct platform_device_id bxt_wcove_tmu_id_table[] = {
+ { .name = "bxt_wcove_tmu" },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, bxt_wcove_tmu_id_table);
+
+static struct platform_driver bxt_wcove_tmu_driver = {
+ .probe = bxt_wcove_tmu_probe,
+ .remove = bxt_wcove_tmu_remove,
+ .driver = {
+ .name = "bxt_wcove_tmu",
+ .pm = &bxtwc_tmu_pm_ops,
+ },
+ .id_table = bxt_wcove_tmu_id_table,
+};
+
+module_platform_driver(bxt_wcove_tmu_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Nilesh Bacchewar <nilesh.bacchewar@intel.com>");
+MODULE_DESCRIPTION("BXT Whiskey Cove TMU Driver");
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c
new file mode 100644
index 000000000000..97b4c3a219c0
--- /dev/null
+++ b/drivers/platform/x86/mlx-platform.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/device.h>
+#include <linux/dmi.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/i2c-mux-reg.h>
+#include <linux/platform_data/mlxcpld-hotplug.h>
+
+#define MLX_PLAT_DEVICE_NAME "mlxplat"
+
+/* LPC bus IO offsets */
+#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000
+#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500
+#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
+#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
+#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
+#define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL
+#define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
+ MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \
+ MLXPLAT_CPLD_LPC_PIO_OFFSET)
+#define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
+ MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \
+ MLXPLAT_CPLD_LPC_PIO_OFFSET)
+
+/* Start channel numbers */
+#define MLXPLAT_CPLD_CH1 2
+#define MLXPLAT_CPLD_CH2 10
+
+/* Number of LPC attached MUX platform devices */
+#define MLXPLAT_CPLD_LPC_MUX_DEVS 2
+
+/* mlxplat_priv - platform private data
+ * @pdev_i2c - i2c controller platform device
+ * @pdev_mux - array of mux platform devices
+ */
+struct mlxplat_priv {
+ struct platform_device *pdev_i2c;
+ struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
+ struct platform_device *pdev_hotplug;
+};
+
+/* Regions for LPC I2C controller and LPC base register space */
+static const struct resource mlxplat_lpc_resources[] = {
+ [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
+ MLXPLAT_CPLD_LPC_IO_RANGE,
+ "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
+ [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
+ MLXPLAT_CPLD_LPC_IO_RANGE,
+ "mlxplat_cpld_lpc_regs",
+ IORESOURCE_IO),
+};
+
+/* Platform default channels */
+static const int mlxplat_default_channels[][8] = {
+ {
+ MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
+ MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
+ 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
+ },
+ {
+ MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
+ MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
+ 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
+ },
+};
+
+/* Platform channels for MSN21xx system family */
+static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+
+/* Platform mux data */
+static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
+ {
+ .parent = 1,
+ .base_nr = MLXPLAT_CPLD_CH1,
+ .write_only = 1,
+ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
+ .reg_size = 1,
+ .idle_in_use = 1,
+ },
+ {
+ .parent = 1,
+ .base_nr = MLXPLAT_CPLD_CH2,
+ .write_only = 1,
+ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
+ .reg_size = 1,
+ .idle_in_use = 1,
+ },
+
+};
+
+/* Platform hotplug devices */
+static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_psu[] = {
+ {
+ .brdinfo = { I2C_BOARD_INFO("24c02", 0x51) },
+ .bus = 10,
+ },
+ {
+ .brdinfo = { I2C_BOARD_INFO("24c02", 0x50) },
+ .bus = 10,
+ },
+};
+
+static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_pwr[] = {
+ {
+ .brdinfo = { I2C_BOARD_INFO("dps460", 0x59) },
+ .bus = 10,
+ },
+ {
+ .brdinfo = { I2C_BOARD_INFO("dps460", 0x58) },
+ .bus = 10,
+ },
+};
+
+static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_fan[] = {
+ {
+ .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
+ .bus = 11,
+ },
+ {
+ .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
+ .bus = 12,
+ },
+ {
+ .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
+ .bus = 13,
+ },
+ {
+ .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
+ .bus = 14,
+ },
+};
+
+/* Platform hotplug default data */
+static
+struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_hotplug_default_data = {
+ .top_aggr_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x3a),
+ .top_aggr_mask = 0x48,
+ .top_aggr_psu_mask = 0x08,
+ .psu_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x58),
+ .psu_mask = 0x03,
+ .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_psu),
+ .psu = mlxplat_mlxcpld_hotplug_psu,
+ .top_aggr_pwr_mask = 0x08,
+ .pwr_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x64),
+ .pwr_mask = 0x03,
+ .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_pwr),
+ .pwr = mlxplat_mlxcpld_hotplug_pwr,
+ .top_aggr_fan_mask = 0x40,
+ .fan_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x88),
+ .fan_mask = 0x0f,
+ .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_fan),
+ .fan = mlxplat_mlxcpld_hotplug_fan,
+};
+
+/* Platform hotplug MSN21xx system family data */
+static
+struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_hotplug_msn21xx_data = {
+ .top_aggr_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x3a),
+ .top_aggr_mask = 0x04,
+ .top_aggr_pwr_mask = 0x04,
+ .pwr_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x64),
+ .pwr_mask = 0x03,
+ .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_pwr),
+};
+
+static struct resource mlxplat_mlxcpld_hotplug_resources[] = {
+ [0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"),
+};
+
+struct platform_device *mlxplat_dev;
+struct mlxcpld_hotplug_platform_data *mlxplat_hotplug;
+
+static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
+ mlxplat_mux_data[i].values = mlxplat_default_channels[i];
+ mlxplat_mux_data[i].n_values =
+ ARRAY_SIZE(mlxplat_default_channels[i]);
+ }
+ mlxplat_hotplug = &mlxplat_mlxcpld_hotplug_default_data;
+
+ return 1;
+};
+
+static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
+ mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
+ mlxplat_mux_data[i].n_values =
+ ARRAY_SIZE(mlxplat_msn21xx_channels);
+ }
+ mlxplat_hotplug = &mlxplat_mlxcpld_hotplug_msn21xx_data;
+
+ return 1;
+};
+
+static struct dmi_system_id mlxplat_dmi_table[] __initdata = {
+ {
+ .callback = mlxplat_dmi_default_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
+ },
+ },
+ {
+ .callback = mlxplat_dmi_default_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
+ },
+ },
+ {
+ .callback = mlxplat_dmi_default_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
+ },
+ },
+ {
+ .callback = mlxplat_dmi_default_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
+ },
+ },
+ {
+ .callback = mlxplat_dmi_msn21xx_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
+ },
+ },
+ { }
+};
+
+static int __init mlxplat_init(void)
+{
+ struct mlxplat_priv *priv;
+ int i, err;
+
+ if (!dmi_check_system(mlxplat_dmi_table))
+ return -ENODEV;
+
+ mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
+ mlxplat_lpc_resources,
+ ARRAY_SIZE(mlxplat_lpc_resources));
+
+ if (IS_ERR(mlxplat_dev))
+ return PTR_ERR(mlxplat_dev);
+
+ priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
+ GFP_KERNEL);
+ if (!priv) {
+ err = -ENOMEM;
+ goto fail_alloc;
+ }
+ platform_set_drvdata(mlxplat_dev, priv);
+
+ priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
+ NULL, 0);
+ if (IS_ERR(priv->pdev_i2c)) {
+ err = PTR_ERR(priv->pdev_i2c);
+ goto fail_alloc;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
+ priv->pdev_mux[i] = platform_device_register_resndata(
+ &mlxplat_dev->dev,
+ "i2c-mux-reg", i, NULL,
+ 0, &mlxplat_mux_data[i],
+ sizeof(mlxplat_mux_data[i]));
+ if (IS_ERR(priv->pdev_mux[i])) {
+ err = PTR_ERR(priv->pdev_mux[i]);
+ goto fail_platform_mux_register;
+ }
+ }
+
+ priv->pdev_hotplug = platform_device_register_resndata(
+ &mlxplat_dev->dev, "mlxcpld-hotplug", -1,
+ mlxplat_mlxcpld_hotplug_resources,
+ ARRAY_SIZE(mlxplat_mlxcpld_hotplug_resources),
+ mlxplat_hotplug, sizeof(*mlxplat_hotplug));
+ if (IS_ERR(priv->pdev_hotplug)) {
+ err = PTR_ERR(priv->pdev_hotplug);
+ goto fail_platform_mux_register;
+ }
+
+ return 0;
+
+fail_platform_mux_register:
+ for (i--; i > 0 ; i--)
+ platform_device_unregister(priv->pdev_mux[i]);
+ platform_device_unregister(priv->pdev_i2c);
+fail_alloc:
+ platform_device_unregister(mlxplat_dev);
+
+ return err;
+}
+module_init(mlxplat_init);
+
+static void __exit mlxplat_exit(void)
+{
+ struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
+ int i;
+
+ platform_device_unregister(priv->pdev_hotplug);
+
+ for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
+ platform_device_unregister(priv->pdev_mux[i]);
+
+ platform_device_unregister(priv->pdev_i2c);
+ platform_device_unregister(mlxplat_dev);
+}
+module_exit(mlxplat_exit);
+
+MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
+MODULE_DESCRIPTION("Mellanox platform driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:");
+MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:");
+MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:");
+MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:");
+MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:");
diff --git a/drivers/platform/x86/surface3-wmi.c b/drivers/platform/x86/surface3-wmi.c
new file mode 100644
index 000000000000..cbf4d83a7271
--- /dev/null
+++ b/drivers/platform/x86/surface3-wmi.c
@@ -0,0 +1,297 @@
+/*
+ * Driver for the LID cover switch of the Surface 3
+ *
+ * Copyright (c) 2016 Red Hat 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; version 2 of the License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+#include <linux/input.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
+MODULE_DESCRIPTION("Surface 3 platform driver");
+MODULE_LICENSE("GPL");
+
+#define ACPI_BUTTON_HID_LID "PNP0C0D"
+#define SPI_CTL_OBJ_NAME "SPI"
+#define SPI_TS_OBJ_NAME "NTRG"
+
+#define SURFACE3_LID_GUID "F7CC25EC-D20B-404C-8903-0ED4359C18AE"
+
+MODULE_ALIAS("wmi:" SURFACE3_LID_GUID);
+
+static const struct dmi_system_id surface3_dmi_table[] = {
+#if defined(CONFIG_X86)
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
+ },
+ },
+#endif
+ { }
+};
+
+struct surface3_wmi {
+ struct acpi_device *touchscreen_adev;
+ struct acpi_device *pnp0c0d_adev;
+ struct acpi_hotplug_context hp;
+ struct input_dev *input;
+};
+
+static struct platform_device *s3_wmi_pdev;
+
+static struct surface3_wmi s3_wmi;
+
+static DEFINE_MUTEX(s3_wmi_lock);
+
+static int s3_wmi_query_block(const char *guid, int instance, int *ret)
+{
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ acpi_status status;
+ union acpi_object *obj;
+ int error = 0;
+
+ mutex_lock(&s3_wmi_lock);
+ status = wmi_query_block(guid, instance, &output);
+
+ obj = output.pointer;
+
+ if (!obj || obj->type != ACPI_TYPE_INTEGER) {
+ if (obj) {
+ pr_err("query block returned object type: %d - buffer length:%d\n",
+ obj->type,
+ obj->type == ACPI_TYPE_BUFFER ?
+ obj->buffer.length : 0);
+ }
+ error = -EINVAL;
+ goto out_free_unlock;
+ }
+ *ret = obj->integer.value;
+ out_free_unlock:
+ kfree(obj);
+ mutex_unlock(&s3_wmi_lock);
+ return error;
+}
+
+static inline int s3_wmi_query_lid(int *ret)
+{
+ return s3_wmi_query_block(SURFACE3_LID_GUID, 0, ret);
+}
+
+static int s3_wmi_send_lid_state(void)
+{
+ int ret, lid_sw;
+
+ ret = s3_wmi_query_lid(&lid_sw);
+ if (ret)
+ return ret;
+
+ input_report_switch(s3_wmi.input, SW_LID, lid_sw);
+ input_sync(s3_wmi.input);
+
+ return 0;
+}
+
+static int s3_wmi_hp_notify(struct acpi_device *adev, u32 value)
+{
+ return s3_wmi_send_lid_state();
+}
+
+static acpi_status s3_wmi_attach_spi_device(acpi_handle handle,
+ u32 level,
+ void *data,
+ void **return_value)
+{
+ struct acpi_device *adev, **ts_adev;
+
+ if (acpi_bus_get_device(handle, &adev))
+ return AE_OK;
+
+ ts_adev = data;
+
+ if (strncmp(acpi_device_bid(adev), SPI_TS_OBJ_NAME,
+ strlen(SPI_TS_OBJ_NAME)))
+ return AE_OK;
+
+ if (*ts_adev) {
+ pr_err("duplicate entry %s\n", SPI_TS_OBJ_NAME);
+ return AE_OK;
+ }
+
+ *ts_adev = adev;
+
+ return AE_OK;
+}
+
+static int s3_wmi_check_platform_device(struct device *dev, void *data)
+{
+ struct acpi_device *adev, *ts_adev;
+ acpi_handle handle;
+ acpi_status status;
+
+ /* ignore non ACPI devices */
+ handle = ACPI_HANDLE(dev);
+ if (!handle || acpi_bus_get_device(handle, &adev))
+ return 0;
+
+ /* check for LID ACPI switch */
+ if (!strcmp(ACPI_BUTTON_HID_LID, acpi_device_hid(adev))) {
+ s3_wmi.pnp0c0d_adev = adev;
+ return 0;
+ }
+
+ /* ignore non SPI controllers */
+ if (strncmp(acpi_device_bid(adev), SPI_CTL_OBJ_NAME,
+ strlen(SPI_CTL_OBJ_NAME)))
+ return 0;
+
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+ s3_wmi_attach_spi_device, NULL,
+ &ts_adev, NULL);
+ if (ACPI_FAILURE(status))
+ dev_warn(dev, "failed to enumerate SPI slaves\n");
+
+ if (!ts_adev)
+ return 0;
+
+ s3_wmi.touchscreen_adev = ts_adev;
+
+ return 0;
+}
+
+static int s3_wmi_create_and_register_input(struct platform_device *pdev)
+{
+ struct input_dev *input;
+ int error;
+
+ input = devm_input_allocate_device(&pdev->dev);
+ if (!input)
+ return -ENOMEM;
+
+ input->name = "Lid Switch";
+ input->phys = "button/input0";
+ input->id.bustype = BUS_HOST;
+ input->id.product = 0x0005;
+
+ input_set_capability(input, EV_SW, SW_LID);
+
+ error = input_register_device(input);
+ if (error)
+ goto out_err;
+
+ s3_wmi.input = input;
+
+ return 0;
+ out_err:
+ input_free_device(s3_wmi.input);
+ return error;
+}
+
+static int __init s3_wmi_probe(struct platform_device *pdev)
+{
+ int error;
+
+ if (!dmi_check_system(surface3_dmi_table))
+ return -ENODEV;
+
+ memset(&s3_wmi, 0, sizeof(s3_wmi));
+
+ bus_for_each_dev(&platform_bus_type, NULL, NULL,
+ s3_wmi_check_platform_device);
+
+ if (!s3_wmi.touchscreen_adev)
+ return -ENODEV;
+
+ acpi_bus_trim(s3_wmi.pnp0c0d_adev);
+
+ error = s3_wmi_create_and_register_input(pdev);
+ if (error)
+ goto restore_acpi_lid;
+
+ acpi_initialize_hp_context(s3_wmi.touchscreen_adev, &s3_wmi.hp,
+ s3_wmi_hp_notify, NULL);
+
+ s3_wmi_send_lid_state();
+
+ return 0;
+
+ restore_acpi_lid:
+ acpi_bus_scan(s3_wmi.pnp0c0d_adev->handle);
+ return error;
+}
+
+static int s3_wmi_remove(struct platform_device *device)
+{
+ /* remove the hotplug context from the acpi device */
+ s3_wmi.touchscreen_adev->hp = NULL;
+
+ /* reinstall the actual PNPC0C0D LID default handle */
+ acpi_bus_scan(s3_wmi.pnp0c0d_adev->handle);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3_wmi_resume(struct device *dev)
+{
+ s3_wmi_send_lid_state();
+ return 0;
+}
+#endif
+static SIMPLE_DEV_PM_OPS(s3_wmi_pm, NULL, s3_wmi_resume);
+
+static struct platform_driver s3_wmi_driver = {
+ .driver = {
+ .name = "surface3-wmi",
+ .pm = &s3_wmi_pm,
+ },
+ .remove = s3_wmi_remove,
+};
+
+static int __init s3_wmi_init(void)
+{
+ int error;
+
+ s3_wmi_pdev = platform_device_alloc("surface3-wmi", -1);
+ if (!s3_wmi_pdev)
+ return -ENOMEM;
+
+ error = platform_device_add(s3_wmi_pdev);
+ if (error)
+ goto err_device_put;
+
+ error = platform_driver_probe(&s3_wmi_driver, s3_wmi_probe);
+ if (error)
+ goto err_device_del;
+
+ pr_info("Surface 3 WMI Extras loaded\n");
+ return 0;
+
+ err_device_del:
+ platform_device_del(s3_wmi_pdev);
+ err_device_put:
+ platform_device_put(s3_wmi_pdev);
+ return error;
+}
+
+static void __exit s3_wmi_exit(void)
+{
+ platform_device_unregister(s3_wmi_pdev);
+ platform_driver_unregister(&s3_wmi_driver);
+}
+
+module_init(s3_wmi_init);
+module_exit(s3_wmi_exit);
diff --git a/drivers/platform/x86/surface3_button.c b/drivers/platform/x86/surface3_button.c
new file mode 100644
index 000000000000..8bfd7f613d36
--- /dev/null
+++ b/drivers/platform/x86/surface3_button.c
@@ -0,0 +1,250 @@
+/*
+ * Supports for the button array on the Surface tablets.
+ *
+ * (C) Copyright 2016 Red Hat, Inc
+ *
+ * Based on soc_button_array.c:
+ *
+ * {C} Copyright 2014 Intel Corporation
+ *
+ * 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; version 2
+ * of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio_keys.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+
+
+#define SURFACE_BUTTON_OBJ_NAME "TEV2"
+#define MAX_NBUTTONS 4
+
+/*
+ * Some of the buttons like volume up/down are auto repeat, while others
+ * are not. To support both, we register two platform devices, and put
+ * buttons into them based on whether the key should be auto repeat.
+ */
+#define BUTTON_TYPES 2
+
+/*
+ * Power button, Home button, Volume buttons support is supposed to
+ * be covered by drivers/input/misc/soc_button_array.c, which is implemented
+ * according to "Windows ACPI Design Guide for SoC Platforms".
+ * However surface 3 seems not to obey the specs, instead it uses
+ * device TEV2(MSHW0028) for declaring the GPIOs. The gpios are also slightly
+ * different in which the Home button is active high.
+ * Compared to surfacepro3_button.c which also handles MSHW0028, the Surface 3
+ * is a reduce platform and thus uses GPIOs, not ACPI events.
+ * We choose an I2C driver here because we need to access the resources
+ * declared under the device node, while surfacepro3_button.c only needs
+ * the ACPI companion node.
+ */
+static const struct acpi_device_id surface3_acpi_match[] = {
+ { "MSHW0028", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, surface3_acpi_match);
+
+struct surface3_button_info {
+ const char *name;
+ int acpi_index;
+ unsigned int event_type;
+ unsigned int event_code;
+ bool autorepeat;
+ bool wakeup;
+ bool active_low;
+};
+
+struct surface3_button_data {
+ struct platform_device *children[BUTTON_TYPES];
+};
+
+/*
+ * Get the Nth GPIO number from the ACPI object.
+ */
+static int surface3_button_lookup_gpio(struct device *dev, int acpi_index)
+{
+ struct gpio_desc *desc;
+ int gpio;
+
+ desc = gpiod_get_index(dev, NULL, acpi_index, GPIOD_ASIS);
+ if (IS_ERR(desc))
+ return PTR_ERR(desc);
+
+ gpio = desc_to_gpio(desc);
+
+ gpiod_put(desc);
+
+ return gpio;
+}
+
+static struct platform_device *
+surface3_button_device_create(struct i2c_client *client,
+ const struct surface3_button_info *button_info,
+ bool autorepeat)
+{
+ const struct surface3_button_info *info;
+ struct platform_device *pd;
+ struct gpio_keys_button *gpio_keys;
+ struct gpio_keys_platform_data *gpio_keys_pdata;
+ int n_buttons = 0;
+ int gpio;
+ int error;
+
+ gpio_keys_pdata = devm_kzalloc(&client->dev,
+ sizeof(*gpio_keys_pdata) +
+ sizeof(*gpio_keys) * MAX_NBUTTONS,
+ GFP_KERNEL);
+ if (!gpio_keys_pdata)
+ return ERR_PTR(-ENOMEM);
+
+ gpio_keys = (void *)(gpio_keys_pdata + 1);
+
+ for (info = button_info; info->name; info++) {
+ if (info->autorepeat != autorepeat)
+ continue;
+
+ gpio = surface3_button_lookup_gpio(&client->dev,
+ info->acpi_index);
+ if (!gpio_is_valid(gpio))
+ continue;
+
+ gpio_keys[n_buttons].type = info->event_type;
+ gpio_keys[n_buttons].code = info->event_code;
+ gpio_keys[n_buttons].gpio = gpio;
+ gpio_keys[n_buttons].active_low = info->active_low;
+ gpio_keys[n_buttons].desc = info->name;
+ gpio_keys[n_buttons].wakeup = info->wakeup;
+ n_buttons++;
+ }
+
+ if (n_buttons == 0) {
+ error = -ENODEV;
+ goto err_free_mem;
+ }
+
+ gpio_keys_pdata->buttons = gpio_keys;
+ gpio_keys_pdata->nbuttons = n_buttons;
+ gpio_keys_pdata->rep = autorepeat;
+
+ pd = platform_device_alloc("gpio-keys", PLATFORM_DEVID_AUTO);
+ if (!pd) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ error = platform_device_add_data(pd, gpio_keys_pdata,
+ sizeof(*gpio_keys_pdata));
+ if (error)
+ goto err_free_pdev;
+
+ error = platform_device_add(pd);
+ if (error)
+ goto err_free_pdev;
+
+ return pd;
+
+err_free_pdev:
+ platform_device_put(pd);
+err_free_mem:
+ devm_kfree(&client->dev, gpio_keys_pdata);
+ return ERR_PTR(error);
+}
+
+static int surface3_button_remove(struct i2c_client *client)
+{
+ struct surface3_button_data *priv = i2c_get_clientdata(client);
+
+ int i;
+
+ for (i = 0; i < BUTTON_TYPES; i++)
+ if (priv->children[i])
+ platform_device_unregister(priv->children[i]);
+
+ return 0;
+}
+
+static struct surface3_button_info surface3_button_surface3[] = {
+ { "power", 0, EV_KEY, KEY_POWER, false, true, true },
+ { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, false },
+ { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
+ { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
+ { }
+};
+
+static int surface3_button_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct surface3_button_data *priv;
+ struct platform_device *pd;
+ int i;
+ int error;
+
+ if (strncmp(acpi_device_bid(ACPI_COMPANION(&client->dev)),
+ SURFACE_BUTTON_OBJ_NAME,
+ strlen(SURFACE_BUTTON_OBJ_NAME)))
+ return -ENODEV;
+
+ if (gpiod_count(dev, KBUILD_MODNAME) <= 0) {
+ dev_dbg(dev, "no GPIO attached, ignoring...\n");
+ return -ENODEV;
+ }
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, priv);
+
+ for (i = 0; i < BUTTON_TYPES; i++) {
+ pd = surface3_button_device_create(client,
+ surface3_button_surface3,
+ i == 0);
+ if (IS_ERR(pd)) {
+ error = PTR_ERR(pd);
+ if (error != -ENODEV) {
+ surface3_button_remove(client);
+ return error;
+ }
+ continue;
+ }
+
+ priv->children[i] = pd;
+ }
+
+ if (!priv->children[0] && !priv->children[1])
+ return -ENODEV;
+
+ return 0;
+}
+
+static const struct i2c_device_id surface3_id[] = {
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, surface3_id);
+
+static struct i2c_driver surface3_driver = {
+ .probe = surface3_button_probe,
+ .remove = surface3_button_remove,
+ .id_table = surface3_id,
+ .driver = {
+ .name = "surface3",
+ .acpi_match_table = ACPI_PTR(surface3_acpi_match),
+ },
+};
+module_i2c_driver(surface3_driver);
+
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
+MODULE_DESCRIPTION("surface3 button array driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c
index eb0f5b13841a..9aafbb03482d 100644
--- a/drivers/regulator/tps65218-regulator.c
+++ b/drivers/regulator/tps65218-regulator.c
@@ -22,6 +22,7 @@
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
+#include <linux/regmap.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
@@ -30,10 +31,11 @@
enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4,
DCDC5, DCDC6, LDO1, LS3 };
-#define TPS65218_REGULATOR(_name, _id, _type, _ops, _n, _vr, _vm, _er, _em, \
- _cr, _cm, _lr, _nlr, _delay, _fuv, _sr, _sm) \
+#define TPS65218_REGULATOR(_name, _of, _id, _type, _ops, _n, _vr, _vm, _er, \
+ _em, _cr, _cm, _lr, _nlr, _delay, _fuv, _sr, _sm) \
{ \
.name = _name, \
+ .of_match = _of, \
.id = _id, \
.ops = &_ops, \
.n_voltages = _n, \
@@ -54,14 +56,6 @@ enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4,
.bypass_mask = _sm, \
} \
-#define TPS65218_INFO(_id, _nm, _min, _max) \
- [_id] = { \
- .id = _id, \
- .name = _nm, \
- .min_uV = _min, \
- .max_uV = _max, \
- }
-
static const struct regulator_linear_range dcdc1_dcdc2_ranges[] = {
REGULATOR_LINEAR_RANGE(850000, 0x0, 0x32, 10000),
REGULATOR_LINEAR_RANGE(1375000, 0x33, 0x3f, 25000),
@@ -77,36 +71,6 @@ static const struct regulator_linear_range dcdc4_ranges[] = {
REGULATOR_LINEAR_RANGE(1600000, 0x10, 0x34, 50000),
};
-static struct tps_info tps65218_pmic_regs[] = {
- TPS65218_INFO(DCDC1, "DCDC1", 850000, 1675000),
- TPS65218_INFO(DCDC2, "DCDC2", 850000, 1675000),
- TPS65218_INFO(DCDC3, "DCDC3", 900000, 3400000),
- TPS65218_INFO(DCDC4, "DCDC4", 1175000, 3400000),
- TPS65218_INFO(DCDC5, "DCDC5", 1000000, 1000000),
- TPS65218_INFO(DCDC6, "DCDC6", 1800000, 1800000),
- TPS65218_INFO(LDO1, "LDO1", 900000, 3400000),
- TPS65218_INFO(LS3, "LS3", -1, -1),
-};
-
-#define TPS65218_OF_MATCH(comp, label) \
- { \
- .compatible = comp, \
- .data = &label, \
- }
-
-static const struct of_device_id tps65218_of_match[] = {
- TPS65218_OF_MATCH("ti,tps65218-dcdc1", tps65218_pmic_regs[DCDC1]),
- TPS65218_OF_MATCH("ti,tps65218-dcdc2", tps65218_pmic_regs[DCDC2]),
- TPS65218_OF_MATCH("ti,tps65218-dcdc3", tps65218_pmic_regs[DCDC3]),
- TPS65218_OF_MATCH("ti,tps65218-dcdc4", tps65218_pmic_regs[DCDC4]),
- TPS65218_OF_MATCH("ti,tps65218-dcdc5", tps65218_pmic_regs[DCDC5]),
- TPS65218_OF_MATCH("ti,tps65218-dcdc6", tps65218_pmic_regs[DCDC6]),
- TPS65218_OF_MATCH("ti,tps65218-ldo1", tps65218_pmic_regs[LDO1]),
- TPS65218_OF_MATCH("ti,tps65218-ls3", tps65218_pmic_regs[LS3]),
- { }
-};
-MODULE_DEVICE_TABLE(of, tps65218_of_match);
-
static int tps65218_pmic_set_voltage_sel(struct regulator_dev *dev,
unsigned selector)
{
@@ -188,7 +152,7 @@ static int tps65218_pmic_set_suspend_disable(struct regulator_dev *dev)
if (rid == TPS65218_DCDC_3 && tps->rev == TPS65218_REV_2_1)
return 0;
- if (!tps->info[rid]->strobe) {
+ if (!tps->strobes[rid]) {
if (rid == TPS65218_DCDC_3)
tps->info[rid]->strobe = 3;
else
@@ -197,8 +161,7 @@ static int tps65218_pmic_set_suspend_disable(struct regulator_dev *dev)
return tps65218_set_bits(tps, dev->desc->bypass_reg,
dev->desc->bypass_mask,
- tps->info[rid]->strobe,
- TPS65218_PROTECT_L1);
+ tps->strobes[rid], TPS65218_PROTECT_L1);
}
/* Operations permitted on DCDC1, DCDC2 */
@@ -272,7 +235,7 @@ static int tps65218_pmic_get_current_limit(struct regulator_dev *dev)
unsigned int index;
struct tps65218 *tps = rdev_get_drvdata(dev);
- retval = tps65218_reg_read(tps, dev->desc->csel_reg, &index);
+ retval = regmap_read(tps->regmap, dev->desc->csel_reg, &index);
if (retval < 0)
return retval;
@@ -300,104 +263,104 @@ static struct regulator_ops tps65218_dcdc56_pmic_ops = {
};
static const struct regulator_desc regulators[] = {
- TPS65218_REGULATOR("DCDC1", TPS65218_DCDC_1, REGULATOR_VOLTAGE,
- tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC1,
+ TPS65218_REGULATOR("DCDC1", "regulator-dcdc1", TPS65218_DCDC_1,
+ REGULATOR_VOLTAGE, tps65218_dcdc12_ops, 64,
+ TPS65218_REG_CONTROL_DCDC1,
TPS65218_CONTROL_DCDC1_MASK, TPS65218_REG_ENABLE1,
TPS65218_ENABLE1_DC1_EN, 0, 0, dcdc1_dcdc2_ranges,
2, 4000, 0, TPS65218_REG_SEQ3,
TPS65218_SEQ3_DC1_SEQ_MASK),
- TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, REGULATOR_VOLTAGE,
- tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC2,
+ TPS65218_REGULATOR("DCDC2", "regulator-dcdc2", TPS65218_DCDC_2,
+ REGULATOR_VOLTAGE, tps65218_dcdc12_ops, 64,
+ TPS65218_REG_CONTROL_DCDC2,
TPS65218_CONTROL_DCDC2_MASK, TPS65218_REG_ENABLE1,
TPS65218_ENABLE1_DC2_EN, 0, 0, dcdc1_dcdc2_ranges,
2, 4000, 0, TPS65218_REG_SEQ3,
TPS65218_SEQ3_DC2_SEQ_MASK),
- TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, REGULATOR_VOLTAGE,
- tps65218_ldo1_dcdc34_ops, 64,
+ TPS65218_REGULATOR("DCDC3", "regulator-dcdc3", TPS65218_DCDC_3,
+ REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 64,
TPS65218_REG_CONTROL_DCDC3,
TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1,
TPS65218_ENABLE1_DC3_EN, 0, 0, ldo1_dcdc3_ranges, 2,
0, 0, TPS65218_REG_SEQ4, TPS65218_SEQ4_DC3_SEQ_MASK),
- TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, REGULATOR_VOLTAGE,
- tps65218_ldo1_dcdc34_ops, 53,
+ TPS65218_REGULATOR("DCDC4", "regulator-dcdc4", TPS65218_DCDC_4,
+ REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 53,
TPS65218_REG_CONTROL_DCDC4,
TPS65218_CONTROL_DCDC4_MASK, TPS65218_REG_ENABLE1,
TPS65218_ENABLE1_DC4_EN, 0, 0, dcdc4_ranges, 2,
0, 0, TPS65218_REG_SEQ4, TPS65218_SEQ4_DC4_SEQ_MASK),
- TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, REGULATOR_VOLTAGE,
- tps65218_dcdc56_pmic_ops, 1, -1, -1,
- TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC5_EN, 0, 0,
- NULL, 0, 0, 1000000, TPS65218_REG_SEQ5,
+ TPS65218_REGULATOR("DCDC5", "regulator-dcdc5", TPS65218_DCDC_5,
+ REGULATOR_VOLTAGE, tps65218_dcdc56_pmic_ops, 1, -1,
+ -1, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC5_EN, 0,
+ 0, NULL, 0, 0, 1000000, TPS65218_REG_SEQ5,
TPS65218_SEQ5_DC5_SEQ_MASK),
- TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, REGULATOR_VOLTAGE,
- tps65218_dcdc56_pmic_ops, 1, -1, -1,
- TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC6_EN, 0, 0,
- NULL, 0, 0, 1800000, TPS65218_REG_SEQ5,
+ TPS65218_REGULATOR("DCDC6", "regulator-dcdc6", TPS65218_DCDC_6,
+ REGULATOR_VOLTAGE, tps65218_dcdc56_pmic_ops, 1, -1,
+ -1, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC6_EN, 0,
+ 0, NULL, 0, 0, 1800000, TPS65218_REG_SEQ5,
TPS65218_SEQ5_DC6_SEQ_MASK),
- TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, REGULATOR_VOLTAGE,
- tps65218_ldo1_dcdc34_ops, 64,
+ TPS65218_REGULATOR("LDO1", "regulator-ldo1", TPS65218_LDO_1,
+ REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 64,
TPS65218_REG_CONTROL_LDO1,
TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2,
TPS65218_ENABLE2_LDO1_EN, 0, 0, ldo1_dcdc3_ranges,
2, 0, 0, TPS65218_REG_SEQ6,
TPS65218_SEQ6_LDO1_SEQ_MASK),
- TPS65218_REGULATOR("LS3", TPS65218_LS_3, REGULATOR_CURRENT,
- tps65218_ls3_ops, 0, 0, 0, TPS65218_REG_ENABLE2,
- TPS65218_ENABLE2_LS3_EN, TPS65218_REG_CONFIG2,
- TPS65218_CONFIG2_LS3ILIM_MASK, NULL, 0, 0, 0, 0, 0),
+ TPS65218_REGULATOR("LS3", "regulator-ls3", TPS65218_LS_3,
+ REGULATOR_CURRENT, tps65218_ls3_ops, 0, 0, 0,
+ TPS65218_REG_ENABLE2, TPS65218_ENABLE2_LS3_EN,
+ TPS65218_REG_CONFIG2, TPS65218_CONFIG2_LS3ILIM_MASK,
+ NULL, 0, 0, 0, 0, 0),
};
static int tps65218_regulator_probe(struct platform_device *pdev)
{
struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent);
- struct regulator_init_data *init_data;
- const struct tps_info *template;
struct regulator_dev *rdev;
- const struct of_device_id *match;
struct regulator_config config = { };
- int id, ret;
+ int i, ret;
unsigned int val;
- match = of_match_device(tps65218_of_match, &pdev->dev);
- if (!match)
- return -ENODEV;
-
- template = match->data;
- id = template->id;
- init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node,
- &regulators[id]);
-
- platform_set_drvdata(pdev, tps);
-
- tps->info[id] = &tps65218_pmic_regs[id];
config.dev = &pdev->dev;
- config.init_data = init_data;
+ config.dev->of_node = tps->dev->of_node;
config.driver_data = tps;
config.regmap = tps->regmap;
- config.of_node = pdev->dev.of_node;
- rdev = devm_regulator_register(&pdev->dev, &regulators[id], &config);
- if (IS_ERR(rdev)) {
- dev_err(tps->dev, "failed to register %s regulator\n",
- pdev->name);
- return PTR_ERR(rdev);
- }
+ /* Allocate memory for strobes */
+ tps->strobes = devm_kzalloc(&pdev->dev, sizeof(u8) *
+ TPS65218_NUM_REGULATOR, GFP_KERNEL);
- ret = tps65218_reg_read(tps, regulators[id].bypass_reg, &val);
- if (ret)
- return ret;
+ for (i = 0; i < ARRAY_SIZE(regulators); i++) {
+ rdev = devm_regulator_register(&pdev->dev, &regulators[i],
+ &config);
+ if (IS_ERR(rdev)) {
+ dev_err(tps->dev, "failed to register %s regulator\n",
+ pdev->name);
+ return PTR_ERR(rdev);
+ }
- tps->info[id]->strobe = val & regulators[id].bypass_mask;
+ ret = regmap_read(tps->regmap, regulators[i].bypass_reg, &val);
+ if (ret)
+ return ret;
+
+ tps->strobes[i] = val & regulators[i].bypass_mask;
+ }
return 0;
}
+static const struct platform_device_id tps65218_regulator_id_table[] = {
+ { "tps65218-regulator", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, tps65218_regulator_id_table);
+
static struct platform_driver tps65218_regulator_driver = {
.driver = {
.name = "tps65218-pmic",
- .of_match_table = tps65218_of_match,
},
.probe = tps65218_regulator_probe,
+ .id_table = tps65218_regulator_id_table,
};
module_platform_driver(tps65218_regulator_driver);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index e859d148aba9..c93c5a8fba32 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -303,7 +303,7 @@ config RTC_DRV_MAX6900
config RTC_DRV_MAX8907
tristate "Maxim MAX8907"
- depends on MFD_MAX8907
+ depends on MFD_MAX8907 || COMPILE_TEST
help
If you say yes here you will get support for the
RTC of Maxim MAX8907 PMIC.
@@ -343,7 +343,7 @@ config RTC_DRV_MAX8997
config RTC_DRV_MAX77686
tristate "Maxim MAX77686"
- depends on MFD_MAX77686 || MFD_MAX77620
+ depends on MFD_MAX77686 || MFD_MAX77620 || COMPILE_TEST
help
If you say yes here you will get support for the
RTC of Maxim MAX77686/MAX77620/MAX77802 PMIC.
@@ -481,6 +481,7 @@ config RTC_DRV_TWL92330
config RTC_DRV_TWL4030
tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0"
depends on TWL4030_CORE
+ depends on OF
help
If you say yes here you get support for the RTC on the
TWL4030/TWL5030/TWL6030 family chips, used mostly with OMAP3 platforms.
@@ -602,7 +603,8 @@ config RTC_DRV_RV8803
config RTC_DRV_S5M
tristate "Samsung S2M/S5M series"
- depends on MFD_SEC_CORE
+ depends on MFD_SEC_CORE || COMPILE_TEST
+ select REGMAP_IRQ
help
If you say yes here you will get support for the
RTC of Samsung S2MPS14 and S5M PMIC series.
@@ -820,8 +822,8 @@ config RTC_DRV_RV3029_HWMON
comment "Platform RTC drivers"
-# this 'CMOS' RTC driver is arch dependent because <asm-generic/rtc.h>
-# requires <asm/mc146818rtc.h> defining CMOS_READ/CMOS_WRITE, and a
+# this 'CMOS' RTC driver is arch dependent because it requires
+# <asm/mc146818rtc.h> defining CMOS_READ/CMOS_WRITE, and a
# global rtc_lock ... it's not yet just another platform_device.
config RTC_DRV_CMOS
@@ -1549,14 +1551,11 @@ config RTC_DRV_MPC5121
will be called rtc-mpc5121.
config RTC_DRV_JZ4740
- tristate "Ingenic JZ4740 SoC"
- depends on MACH_JZ4740 || COMPILE_TEST
+ bool "Ingenic JZ4740 SoC"
+ depends on MACH_INGENIC || COMPILE_TEST
help
- If you say yes here you get support for the Ingenic JZ4740 SoC RTC
- controller.
-
- This driver can also be buillt as a module. If so, the module
- will be called rtc-jz4740.
+ If you say yes here you get support for the Ingenic JZ47xx SoCs RTC
+ controllers.
config RTC_DRV_LPC24XX
tristate "NXP RTC for LPC178x/18xx/408x/43xx"
@@ -1567,7 +1566,7 @@ config RTC_DRV_LPC24XX
NXP LPC178x/18xx/408x/43xx devices.
If you have one of the devices above enable this driver to use
- the hardware RTC. This driver can also be buillt as a module. If
+ the hardware RTC. This driver can also be built as a module. If
so, the module will be called rtc-lpc24xx.
config RTC_DRV_LPC32XX
@@ -1576,7 +1575,7 @@ config RTC_DRV_LPC32XX
help
This enables support for the NXP RTC in the LPC32XX
- This driver can also be buillt as a module. If so, the module
+ This driver can also be built as a module. If so, the module
will be called rtc-lpc32xx.
config RTC_DRV_PM8XXX
@@ -1706,6 +1705,17 @@ config RTC_DRV_PIC32
This driver can also be built as a module. If so, the module
will be called rtc-pic32
+config RTC_DRV_R7301
+ tristate "EPSON TOYOCOM RTC-7301SF/DG"
+ select REGMAP_MMIO
+ depends on OF && HAS_IOMEM
+ help
+ If you say yes here you get support for the EPSON TOYOCOM
+ RTC-7301SF/DG chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-r7301.
+
comment "HID Sensor RTC drivers"
config RTC_DRV_HID_SENSOR_TIME
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 1ac694a330c8..f13ab1c5c222 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -120,6 +120,7 @@ obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o
obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o
obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o
obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
+obj-$(CONFIG_RTC_DRV_R7301) += rtc-r7301.o
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5t583.o
obj-$(CONFIG_RTC_DRV_RK808) += rtc-rk808.o
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 38aa8e1906c2..f4a96dbdabf2 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -332,14 +332,86 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask)
cmos_checkintr(cmos, rtc_control);
}
+static int cmos_validate_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct cmos_rtc *cmos = dev_get_drvdata(dev);
+ struct rtc_time now;
+
+ cmos_read_time(dev, &now);
+
+ if (!cmos->day_alrm) {
+ time64_t t_max_date;
+ time64_t t_alrm;
+
+ t_max_date = rtc_tm_to_time64(&now);
+ t_max_date += 24 * 60 * 60 - 1;
+ t_alrm = rtc_tm_to_time64(&t->time);
+ if (t_alrm > t_max_date) {
+ dev_err(dev,
+ "Alarms can be up to one day in the future\n");
+ return -EINVAL;
+ }
+ } else if (!cmos->mon_alrm) {
+ struct rtc_time max_date = now;
+ time64_t t_max_date;
+ time64_t t_alrm;
+ int max_mday;
+
+ if (max_date.tm_mon == 11) {
+ max_date.tm_mon = 0;
+ max_date.tm_year += 1;
+ } else {
+ max_date.tm_mon += 1;
+ }
+ max_mday = rtc_month_days(max_date.tm_mon, max_date.tm_year);
+ if (max_date.tm_mday > max_mday)
+ max_date.tm_mday = max_mday;
+
+ t_max_date = rtc_tm_to_time64(&max_date);
+ t_max_date -= 1;
+ t_alrm = rtc_tm_to_time64(&t->time);
+ if (t_alrm > t_max_date) {
+ dev_err(dev,
+ "Alarms can be up to one month in the future\n");
+ return -EINVAL;
+ }
+ } else {
+ struct rtc_time max_date = now;
+ time64_t t_max_date;
+ time64_t t_alrm;
+ int max_mday;
+
+ max_date.tm_year += 1;
+ max_mday = rtc_month_days(max_date.tm_mon, max_date.tm_year);
+ if (max_date.tm_mday > max_mday)
+ max_date.tm_mday = max_mday;
+
+ t_max_date = rtc_tm_to_time64(&max_date);
+ t_max_date -= 1;
+ t_alrm = rtc_tm_to_time64(&t->time);
+ if (t_alrm > t_max_date) {
+ dev_err(dev,
+ "Alarms can be up to one year in the future\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char mon, mday, hrs, min, sec, rtc_control;
+ int ret;
if (!is_valid_irq(cmos->irq))
return -EIO;
+ ret = cmos_validate_alarm(dev, t);
+ if (ret < 0)
+ return ret;
+
mon = t->time.tm_mon + 1;
mday = t->time.tm_mday;
hrs = t->time.tm_hour;
@@ -707,9 +779,6 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
spin_unlock_irq(&rtc_lock);
- /* FIXME:
- * <asm-generic/rtc.h> doesn't know 12-hour mode either.
- */
if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) {
dev_warn(dev, "only 24-hr supported\n");
retval = -ENXIO;
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 4e31036ee259..4ad97be48043 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -11,6 +11,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/acpi.h>
#include <linux/bcd.h>
#include <linux/i2c.h>
#include <linux/init.h>
@@ -191,6 +192,26 @@ static const struct i2c_device_id ds1307_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ds1307_id);
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id ds1307_acpi_ids[] = {
+ { .id = "DS1307", .driver_data = ds_1307 },
+ { .id = "DS1337", .driver_data = ds_1337 },
+ { .id = "DS1338", .driver_data = ds_1338 },
+ { .id = "DS1339", .driver_data = ds_1339 },
+ { .id = "DS1388", .driver_data = ds_1388 },
+ { .id = "DS1340", .driver_data = ds_1340 },
+ { .id = "DS3231", .driver_data = ds_3231 },
+ { .id = "M41T00", .driver_data = m41t00 },
+ { .id = "MCP7940X", .driver_data = mcp794xx },
+ { .id = "MCP7941X", .driver_data = mcp794xx },
+ { .id = "PT7C4338", .driver_data = ds_1307 },
+ { .id = "RX8025", .driver_data = rx_8025 },
+ { .id = "ISL12057", .driver_data = ds_1337 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, ds1307_acpi_ids);
+#endif
+
/*----------------------------------------------------------------------*/
#define BLOCK_DATA_MAX_TRIES 10
@@ -874,17 +895,17 @@ static u8 do_trickle_setup_ds1339(struct i2c_client *client,
return setup;
}
-static void ds1307_trickle_of_init(struct i2c_client *client,
- struct chip_desc *chip)
+static void ds1307_trickle_init(struct i2c_client *client,
+ struct chip_desc *chip)
{
uint32_t ohms = 0;
bool diode = true;
if (!chip->do_trickle_setup)
goto out;
- if (of_property_read_u32(client->dev.of_node, "trickle-resistor-ohms" , &ohms))
+ if (device_property_read_u32(&client->dev, "trickle-resistor-ohms", &ohms))
goto out;
- if (of_property_read_bool(client->dev.of_node, "trickle-diode-disable"))
+ if (device_property_read_bool(&client->dev, "trickle-diode-disable"))
diode = false;
chip->trickle_charger_setup = chip->do_trickle_setup(client,
ohms, diode);
@@ -1268,7 +1289,7 @@ static int ds1307_probe(struct i2c_client *client,
struct ds1307 *ds1307;
int err = -ENODEV;
int tmp, wday;
- struct chip_desc *chip = &chips[id->driver_data];
+ struct chip_desc *chip;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
bool want_irq = false;
bool ds1307_can_wakeup_device = false;
@@ -1297,11 +1318,23 @@ static int ds1307_probe(struct i2c_client *client,
i2c_set_clientdata(client, ds1307);
ds1307->client = client;
- ds1307->type = id->driver_data;
+ if (id) {
+ chip = &chips[id->driver_data];
+ ds1307->type = id->driver_data;
+ } else {
+ const struct acpi_device_id *acpi_id;
+
+ acpi_id = acpi_match_device(ACPI_PTR(ds1307_acpi_ids),
+ &client->dev);
+ if (!acpi_id)
+ return -ENODEV;
+ chip = &chips[acpi_id->driver_data];
+ ds1307->type = acpi_id->driver_data;
+ }
- if (!pdata && client->dev.of_node)
- ds1307_trickle_of_init(client, chip);
- else if (pdata && pdata->trickle_charger_setup)
+ if (!pdata)
+ ds1307_trickle_init(client, chip);
+ else if (pdata->trickle_charger_setup)
chip->trickle_charger_setup = pdata->trickle_charger_setup;
if (chip->trickle_charger_setup && chip->trickle_charger_reg) {
@@ -1678,6 +1711,7 @@ static int ds1307_remove(struct i2c_client *client)
static struct i2c_driver ds1307_driver = {
.driver = {
.name = "rtc-ds1307",
+ .acpi_match_table = ACPI_PTR(ds1307_acpi_ids),
},
.probe = ds1307_probe,
.remove = ds1307_remove,
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index 3b3049c8c9e0..52429f0a57cc 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -89,10 +89,8 @@ static int ds1374_read_rtc(struct i2c_client *client, u32 *time,
int ret;
int i;
- if (nbytes > 4) {
- WARN_ON(1);
+ if (WARN_ON(nbytes > 4))
return -EINVAL;
- }
ret = i2c_smbus_read_i2c_block_data(client, reg, nbytes, buf);
diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c
index 8d8049bdfaf6..67b56b80dc70 100644
--- a/drivers/rtc/rtc-imxdi.c
+++ b/drivers/rtc/rtc-imxdi.c
@@ -67,7 +67,7 @@
#define DSR_ETAD (1 << 21) /* External tamper A detected */
#define DSR_EBD (1 << 20) /* External boot detected */
#define DSR_SAD (1 << 19) /* SCC alarm detected */
-#define DSR_TTD (1 << 18) /* Temperatur tamper detected */
+#define DSR_TTD (1 << 18) /* Temperature tamper detected */
#define DSR_CTD (1 << 17) /* Clock tamper detected */
#define DSR_VTD (1 << 16) /* Voltage tamper detected */
#define DSR_WBF (1 << 10) /* Write Busy Flag (synchronous) */
diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c
index 5e14651b71a8..72918c1ba092 100644
--- a/drivers/rtc/rtc-jz4740.c
+++ b/drivers/rtc/rtc-jz4740.c
@@ -14,10 +14,12 @@
*
*/
+#include <linux/clk.h>
#include <linux/io.h>
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/reboot.h>
#include <linux/rtc.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -27,8 +29,14 @@
#define JZ_REG_RTC_SEC_ALARM 0x08
#define JZ_REG_RTC_REGULATOR 0x0C
#define JZ_REG_RTC_HIBERNATE 0x20
+#define JZ_REG_RTC_WAKEUP_FILTER 0x24
+#define JZ_REG_RTC_RESET_COUNTER 0x28
#define JZ_REG_RTC_SCRATCHPAD 0x34
+/* The following are present on the jz4780 */
+#define JZ_REG_RTC_WENR 0x3C
+#define JZ_RTC_WENR_WEN BIT(31)
+
#define JZ_RTC_CTRL_WRDY BIT(7)
#define JZ_RTC_CTRL_1HZ BIT(6)
#define JZ_RTC_CTRL_1HZ_IRQ BIT(5)
@@ -37,16 +45,34 @@
#define JZ_RTC_CTRL_AE BIT(2)
#define JZ_RTC_CTRL_ENABLE BIT(0)
+/* Magic value to enable writes on jz4780 */
+#define JZ_RTC_WENR_MAGIC 0xA55A
+
+#define JZ_RTC_WAKEUP_FILTER_MASK 0x0000FFE0
+#define JZ_RTC_RESET_COUNTER_MASK 0x00000FE0
+
+enum jz4740_rtc_type {
+ ID_JZ4740,
+ ID_JZ4780,
+};
+
struct jz4740_rtc {
void __iomem *base;
+ enum jz4740_rtc_type type;
struct rtc_device *rtc;
+ struct clk *clk;
int irq;
spinlock_t lock;
+
+ unsigned int min_wakeup_pin_assert_time;
+ unsigned int reset_pin_assert_time;
};
+static struct device *dev_for_power_off;
+
static inline uint32_t jz4740_rtc_reg_read(struct jz4740_rtc *rtc, size_t reg)
{
return readl(rtc->base + reg);
@@ -64,11 +90,33 @@ static int jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc)
return timeout ? 0 : -EIO;
}
+static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc)
+{
+ uint32_t ctrl;
+ int ret, timeout = 1000;
+
+ ret = jz4740_rtc_wait_write_ready(rtc);
+ if (ret != 0)
+ return ret;
+
+ writel(JZ_RTC_WENR_MAGIC, rtc->base + JZ_REG_RTC_WENR);
+
+ do {
+ ctrl = readl(rtc->base + JZ_REG_RTC_WENR);
+ } while (!(ctrl & JZ_RTC_WENR_WEN) && --timeout);
+
+ return timeout ? 0 : -EIO;
+}
+
static inline int jz4740_rtc_reg_write(struct jz4740_rtc *rtc, size_t reg,
uint32_t val)
{
- int ret;
- ret = jz4740_rtc_wait_write_ready(rtc);
+ int ret = 0;
+
+ if (rtc->type >= ID_JZ4780)
+ ret = jz4780_rtc_enable_write(rtc);
+ if (ret == 0)
+ ret = jz4740_rtc_wait_write_ready(rtc);
if (ret == 0)
writel(val, rtc->base + reg);
@@ -203,12 +251,57 @@ static irqreturn_t jz4740_rtc_irq(int irq, void *data)
return IRQ_HANDLED;
}
-void jz4740_rtc_poweroff(struct device *dev)
+static void jz4740_rtc_poweroff(struct device *dev)
{
struct jz4740_rtc *rtc = dev_get_drvdata(dev);
jz4740_rtc_reg_write(rtc, JZ_REG_RTC_HIBERNATE, 1);
}
-EXPORT_SYMBOL_GPL(jz4740_rtc_poweroff);
+
+static void jz4740_rtc_power_off(void)
+{
+ struct jz4740_rtc *rtc = dev_get_drvdata(dev_for_power_off);
+ unsigned long rtc_rate;
+ unsigned long wakeup_filter_ticks;
+ unsigned long reset_counter_ticks;
+
+ clk_prepare_enable(rtc->clk);
+
+ rtc_rate = clk_get_rate(rtc->clk);
+
+ /*
+ * Set minimum wakeup pin assertion time: 100 ms.
+ * Range is 0 to 2 sec if RTC is clocked at 32 kHz.
+ */
+ wakeup_filter_ticks =
+ (rtc->min_wakeup_pin_assert_time * rtc_rate) / 1000;
+ if (wakeup_filter_ticks < JZ_RTC_WAKEUP_FILTER_MASK)
+ wakeup_filter_ticks &= JZ_RTC_WAKEUP_FILTER_MASK;
+ else
+ wakeup_filter_ticks = JZ_RTC_WAKEUP_FILTER_MASK;
+ jz4740_rtc_reg_write(rtc,
+ JZ_REG_RTC_WAKEUP_FILTER, wakeup_filter_ticks);
+
+ /*
+ * Set reset pin low-level assertion time after wakeup: 60 ms.
+ * Range is 0 to 125 ms if RTC is clocked at 32 kHz.
+ */
+ reset_counter_ticks = (rtc->reset_pin_assert_time * rtc_rate) / 1000;
+ if (reset_counter_ticks < JZ_RTC_RESET_COUNTER_MASK)
+ reset_counter_ticks &= JZ_RTC_RESET_COUNTER_MASK;
+ else
+ reset_counter_ticks = JZ_RTC_RESET_COUNTER_MASK;
+ jz4740_rtc_reg_write(rtc,
+ JZ_REG_RTC_RESET_COUNTER, reset_counter_ticks);
+
+ jz4740_rtc_poweroff(dev_for_power_off);
+ machine_halt();
+}
+
+static const struct of_device_id jz4740_rtc_of_match[] = {
+ { .compatible = "ingenic,jz4740-rtc", .data = (void *)ID_JZ4740 },
+ { .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 },
+ {},
+};
static int jz4740_rtc_probe(struct platform_device *pdev)
{
@@ -216,11 +309,20 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
struct jz4740_rtc *rtc;
uint32_t scratchpad;
struct resource *mem;
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+ const struct of_device_id *of_id = of_match_device(
+ jz4740_rtc_of_match, &pdev->dev);
+ struct device_node *np = pdev->dev.of_node;
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
+ if (of_id)
+ rtc->type = (enum jz4740_rtc_type)of_id->data;
+ else
+ rtc->type = id->driver_data;
+
rtc->irq = platform_get_irq(pdev, 0);
if (rtc->irq < 0) {
dev_err(&pdev->dev, "Failed to get platform irq\n");
@@ -232,6 +334,12 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
if (IS_ERR(rtc->base))
return PTR_ERR(rtc->base);
+ rtc->clk = devm_clk_get(&pdev->dev, "rtc");
+ if (IS_ERR(rtc->clk)) {
+ dev_err(&pdev->dev, "Failed to get RTC clock\n");
+ return PTR_ERR(rtc->clk);
+ }
+
spin_lock_init(&rtc->lock);
platform_set_drvdata(pdev, rtc);
@@ -263,6 +371,27 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
}
}
+ if (np && of_device_is_system_power_controller(np)) {
+ if (!pm_power_off) {
+ /* Default: 60ms */
+ rtc->reset_pin_assert_time = 60;
+ of_property_read_u32(np, "reset-pin-assert-time-ms",
+ &rtc->reset_pin_assert_time);
+
+ /* Default: 100ms */
+ rtc->min_wakeup_pin_assert_time = 100;
+ of_property_read_u32(np,
+ "min-wakeup-pin-assert-time-ms",
+ &rtc->min_wakeup_pin_assert_time);
+
+ dev_for_power_off = &pdev->dev;
+ pm_power_off = jz4740_rtc_power_off;
+ } else {
+ dev_warn(&pdev->dev,
+ "Poweroff handler already present!\n");
+ }
+ }
+
return 0;
}
@@ -295,17 +424,20 @@ static const struct dev_pm_ops jz4740_pm_ops = {
#define JZ4740_RTC_PM_OPS NULL
#endif /* CONFIG_PM */
+static const struct platform_device_id jz4740_rtc_ids[] = {
+ { "jz4740-rtc", ID_JZ4740 },
+ { "jz4780-rtc", ID_JZ4780 },
+ {}
+};
+
static struct platform_driver jz4740_rtc_driver = {
.probe = jz4740_rtc_probe,
.driver = {
.name = "jz4740-rtc",
.pm = JZ4740_RTC_PM_OPS,
+ .of_match_table = of_match_ptr(jz4740_rtc_of_match),
},
+ .id_table = jz4740_rtc_ids,
};
-module_platform_driver(jz4740_rtc_driver);
-
-MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("RTC driver for the JZ4740 SoC\n");
-MODULE_ALIAS("platform:jz4740-rtc");
+builtin_platform_driver(jz4740_rtc_driver);
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index e6bfb9c42a10..1ae7da5cfc60 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -11,7 +11,7 @@
* published by the Free Software Foundation.
*/
-#include <linux/module.h>
+#include <linux/export.h>
#include <linux/rtc.h>
static const unsigned char rtc_days_in_month[] = {
@@ -148,5 +148,3 @@ struct rtc_time rtc_ktime_to_tm(ktime_t kt)
return ret;
}
EXPORT_SYMBOL_GPL(rtc_ktime_to_tm);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c
index 4021fd04cb0a..ce75e421ba00 100644
--- a/drivers/rtc/rtc-mcp795.c
+++ b/drivers/rtc/rtc-mcp795.c
@@ -12,7 +12,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * */
+ */
#include <linux/module.h>
#include <linux/kernel.h>
@@ -21,6 +21,8 @@
#include <linux/spi/spi.h>
#include <linux/rtc.h>
#include <linux/of.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
/* MCP795 Instructions, see datasheet table 3-1 */
#define MCP795_EEREAD 0x03
@@ -29,7 +31,7 @@
#define MCP795_EEWREN 0x06
#define MCP795_SRREAD 0x05
#define MCP795_SRWRITE 0x01
-#define MCP795_READ 0x13
+#define MCP795_READ 0x13
#define MCP795_WRITE 0x12
#define MCP795_UNLOCK 0x14
#define MCP795_IDWRITE 0x32
@@ -37,8 +39,17 @@
#define MCP795_CLRWDT 0x44
#define MCP795_CLRRAM 0x54
-#define MCP795_ST_BIT 0x80
-#define MCP795_24_BIT 0x40
+/* MCP795 RTCC registers, see datasheet table 4-1 */
+#define MCP795_REG_SECONDS 0x01
+#define MCP795_REG_DAY 0x04
+#define MCP795_REG_MONTH 0x06
+#define MCP795_REG_CONTROL 0x08
+
+#define MCP795_ST_BIT BIT(7)
+#define MCP795_24_BIT BIT(6)
+#define MCP795_LP_BIT BIT(5)
+#define MCP795_EXTOSC_BIT BIT(3)
+#define MCP795_OSCON_BIT BIT(5)
static int mcp795_rtcc_read(struct device *dev, u8 addr, u8 *buf, u8 count)
{
@@ -93,30 +104,97 @@ static int mcp795_rtcc_set_bits(struct device *dev, u8 addr, u8 mask, u8 state)
return ret;
}
+static int mcp795_stop_oscillator(struct device *dev, bool *extosc)
+{
+ int retries = 5;
+ int ret;
+ u8 data;
+
+ ret = mcp795_rtcc_set_bits(dev, MCP795_REG_SECONDS, MCP795_ST_BIT, 0);
+ if (ret)
+ return ret;
+ ret = mcp795_rtcc_read(dev, MCP795_REG_CONTROL, &data, 1);
+ if (ret)
+ return ret;
+ *extosc = !!(data & MCP795_EXTOSC_BIT);
+ ret = mcp795_rtcc_set_bits(
+ dev, MCP795_REG_CONTROL, MCP795_EXTOSC_BIT, 0);
+ if (ret)
+ return ret;
+ /* wait for the OSCON bit to clear */
+ do {
+ usleep_range(700, 800);
+ ret = mcp795_rtcc_read(dev, MCP795_REG_DAY, &data, 1);
+ if (ret)
+ break;
+ if (!(data & MCP795_OSCON_BIT))
+ break;
+
+ } while (--retries);
+
+ return !retries ? -EIO : ret;
+}
+
+static int mcp795_start_oscillator(struct device *dev, bool *extosc)
+{
+ if (extosc) {
+ u8 data = *extosc ? MCP795_EXTOSC_BIT : 0;
+ int ret;
+
+ ret = mcp795_rtcc_set_bits(
+ dev, MCP795_REG_CONTROL, MCP795_EXTOSC_BIT, data);
+ if (ret)
+ return ret;
+ }
+ return mcp795_rtcc_set_bits(
+ dev, MCP795_REG_SECONDS, MCP795_ST_BIT, MCP795_ST_BIT);
+}
+
static int mcp795_set_time(struct device *dev, struct rtc_time *tim)
{
int ret;
u8 data[7];
+ bool extosc;
+
+ /* Stop RTC and store current value of EXTOSC bit */
+ ret = mcp795_stop_oscillator(dev, &extosc);
+ if (ret)
+ return ret;
/* Read first, so we can leave config bits untouched */
- ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data));
+ ret = mcp795_rtcc_read(dev, MCP795_REG_SECONDS, data, sizeof(data));
if (ret)
return ret;
- data[0] = (data[0] & 0x80) | ((tim->tm_sec / 10) << 4) | (tim->tm_sec % 10);
- data[1] = (data[1] & 0x80) | ((tim->tm_min / 10) << 4) | (tim->tm_min % 10);
- data[2] = ((tim->tm_hour / 10) << 4) | (tim->tm_hour % 10);
- data[4] = ((tim->tm_mday / 10) << 4) | ((tim->tm_mday) % 10);
- data[5] = (data[5] & 0x10) | (tim->tm_mon / 10) | (tim->tm_mon % 10);
+ data[0] = (data[0] & 0x80) | bin2bcd(tim->tm_sec);
+ data[1] = (data[1] & 0x80) | bin2bcd(tim->tm_min);
+ data[2] = bin2bcd(tim->tm_hour);
+ data[4] = bin2bcd(tim->tm_mday);
+ data[5] = (data[5] & MCP795_LP_BIT) | bin2bcd(tim->tm_mon + 1);
if (tim->tm_year > 100)
tim->tm_year -= 100;
- data[6] = ((tim->tm_year / 10) << 4) | (tim->tm_year % 10);
+ data[6] = bin2bcd(tim->tm_year);
+
+ /* Always write the date and month using a separate Write command.
+ * This is a workaround for a know silicon issue that some combinations
+ * of date and month values may result in the date being reset to 1.
+ */
+ ret = mcp795_rtcc_write(dev, MCP795_REG_SECONDS, data, 5);
+ if (ret)
+ return ret;
- ret = mcp795_rtcc_write(dev, 0x01, data, sizeof(data));
+ ret = mcp795_rtcc_write(dev, MCP795_REG_MONTH, &data[5], 2);
+ if (ret)
+ return ret;
+ /* Start back RTC and restore previous value of EXTOSC bit.
+ * There is no need to clear EXTOSC bit when the previous value was 0
+ * because it was already cleared when stopping the RTC oscillator.
+ */
+ ret = mcp795_start_oscillator(dev, extosc ? &extosc : NULL);
if (ret)
return ret;
@@ -132,17 +210,17 @@ static int mcp795_read_time(struct device *dev, struct rtc_time *tim)
int ret;
u8 data[7];
- ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data));
+ ret = mcp795_rtcc_read(dev, MCP795_REG_SECONDS, data, sizeof(data));
if (ret)
return ret;
- tim->tm_sec = ((data[0] & 0x70) >> 4) * 10 + (data[0] & 0x0f);
- tim->tm_min = ((data[1] & 0x70) >> 4) * 10 + (data[1] & 0x0f);
- tim->tm_hour = ((data[2] & 0x30) >> 4) * 10 + (data[2] & 0x0f);
- tim->tm_mday = ((data[4] & 0x30) >> 4) * 10 + (data[4] & 0x0f);
- tim->tm_mon = ((data[5] & 0x10) >> 4) * 10 + (data[5] & 0x0f);
- tim->tm_year = ((data[6] & 0xf0) >> 4) * 10 + (data[6] & 0x0f) + 100; /* Assume we are in 20xx */
+ tim->tm_sec = bcd2bin(data[0] & 0x7F);
+ tim->tm_min = bcd2bin(data[1] & 0x7F);
+ tim->tm_hour = bcd2bin(data[2] & 0x3F);
+ tim->tm_mday = bcd2bin(data[4] & 0x3F);
+ tim->tm_mon = bcd2bin(data[5] & 0x1F) - 1;
+ tim->tm_year = bcd2bin(data[6]) + 100; /* Assume we are in 20xx */
dev_dbg(dev, "Read from mcp795: %04d-%02d-%02d %02d:%02d:%02d\n",
tim->tm_year + 1900, tim->tm_mon, tim->tm_mday,
@@ -169,13 +247,13 @@ static int mcp795_probe(struct spi_device *spi)
return ret;
}
- /* Start the oscillator */
- mcp795_rtcc_set_bits(&spi->dev, 0x01, MCP795_ST_BIT, MCP795_ST_BIT);
+ /* Start the oscillator but don't set the value of EXTOSC bit */
+ mcp795_start_oscillator(&spi->dev, NULL);
/* Clear the 12 hour mode flag*/
mcp795_rtcc_set_bits(&spi->dev, 0x03, MCP795_24_BIT, 0);
rtc = devm_rtc_device_register(&spi->dev, "rtc-mcp795",
- &mcp795_rtc_ops, THIS_MODULE);
+ &mcp795_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index efb0a08ac117..a06dff994c83 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -191,12 +191,19 @@ static int pcf85063_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct rtc_device *rtc;
+ int err;
dev_dbg(&client->dev, "%s\n", __func__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
+ err = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1);
+ if (err < 0) {
+ dev_err(&client->dev, "RTC chip is not present\n");
+ return err;
+ }
+
rtc = devm_rtc_device_register(&client->dev,
pcf85063_driver.driver.name,
&pcf85063_rtc_ops, THIS_MODULE);
diff --git a/drivers/rtc/rtc-r7301.c b/drivers/rtc/rtc-r7301.c
new file mode 100644
index 000000000000..28d540885f3d
--- /dev/null
+++ b/drivers/rtc/rtc-r7301.c
@@ -0,0 +1,453 @@
+/*
+ * EPSON TOYOCOM RTC-7301SF/DG Driver
+ *
+ * Copyright (c) 2016 Akinobu Mita <akinobu.mita@gmail.com>
+ *
+ * Based on rtc-rp5c01.c
+ *
+ * Datasheet: http://www5.epsondevice.com/en/products/parallel/rtc7301sf.html
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+#define DRV_NAME "rtc-r7301"
+
+#define RTC7301_1_SEC 0x0 /* Bank 0 and Band 1 */
+#define RTC7301_10_SEC 0x1 /* Bank 0 and Band 1 */
+#define RTC7301_AE BIT(3)
+#define RTC7301_1_MIN 0x2 /* Bank 0 and Band 1 */
+#define RTC7301_10_MIN 0x3 /* Bank 0 and Band 1 */
+#define RTC7301_1_HOUR 0x4 /* Bank 0 and Band 1 */
+#define RTC7301_10_HOUR 0x5 /* Bank 0 and Band 1 */
+#define RTC7301_DAY_OF_WEEK 0x6 /* Bank 0 and Band 1 */
+#define RTC7301_1_DAY 0x7 /* Bank 0 and Band 1 */
+#define RTC7301_10_DAY 0x8 /* Bank 0 and Band 1 */
+#define RTC7301_1_MONTH 0x9 /* Bank 0 */
+#define RTC7301_10_MONTH 0xa /* Bank 0 */
+#define RTC7301_1_YEAR 0xb /* Bank 0 */
+#define RTC7301_10_YEAR 0xc /* Bank 0 */
+#define RTC7301_100_YEAR 0xd /* Bank 0 */
+#define RTC7301_1000_YEAR 0xe /* Bank 0 */
+#define RTC7301_ALARM_CONTROL 0xe /* Bank 1 */
+#define RTC7301_ALARM_CONTROL_AIE BIT(0)
+#define RTC7301_ALARM_CONTROL_AF BIT(1)
+#define RTC7301_TIMER_CONTROL 0xe /* Bank 2 */
+#define RTC7301_TIMER_CONTROL_TIE BIT(0)
+#define RTC7301_TIMER_CONTROL_TF BIT(1)
+#define RTC7301_CONTROL 0xf /* All banks */
+#define RTC7301_CONTROL_BUSY BIT(0)
+#define RTC7301_CONTROL_STOP BIT(1)
+#define RTC7301_CONTROL_BANK_SEL_0 BIT(2)
+#define RTC7301_CONTROL_BANK_SEL_1 BIT(3)
+
+struct rtc7301_priv {
+ struct regmap *regmap;
+ int irq;
+ spinlock_t lock;
+ u8 bank;
+};
+
+static const struct regmap_config rtc7301_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .reg_stride = 4,
+};
+
+static u8 rtc7301_read(struct rtc7301_priv *priv, unsigned int reg)
+{
+ int reg_stride = regmap_get_reg_stride(priv->regmap);
+ unsigned int val;
+
+ regmap_read(priv->regmap, reg_stride * reg, &val);
+
+ return val & 0xf;
+}
+
+static void rtc7301_write(struct rtc7301_priv *priv, u8 val, unsigned int reg)
+{
+ int reg_stride = regmap_get_reg_stride(priv->regmap);
+
+ regmap_write(priv->regmap, reg_stride * reg, val);
+}
+
+static void rtc7301_update_bits(struct rtc7301_priv *priv, unsigned int reg,
+ u8 mask, u8 val)
+{
+ int reg_stride = regmap_get_reg_stride(priv->regmap);
+
+ regmap_update_bits(priv->regmap, reg_stride * reg, mask, val);
+}
+
+static int rtc7301_wait_while_busy(struct rtc7301_priv *priv)
+{
+ int retries = 100;
+
+ while (retries-- > 0) {
+ u8 val;
+
+ val = rtc7301_read(priv, RTC7301_CONTROL);
+ if (!(val & RTC7301_CONTROL_BUSY))
+ return 0;
+
+ usleep_range(200, 300);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static void rtc7301_stop(struct rtc7301_priv *priv)
+{
+ rtc7301_update_bits(priv, RTC7301_CONTROL, RTC7301_CONTROL_STOP,
+ RTC7301_CONTROL_STOP);
+}
+
+static void rtc7301_start(struct rtc7301_priv *priv)
+{
+ rtc7301_update_bits(priv, RTC7301_CONTROL, RTC7301_CONTROL_STOP, 0);
+}
+
+static void rtc7301_select_bank(struct rtc7301_priv *priv, u8 bank)
+{
+ u8 val = 0;
+
+ if (bank == priv->bank)
+ return;
+
+ if (bank & BIT(0))
+ val |= RTC7301_CONTROL_BANK_SEL_0;
+ if (bank & BIT(1))
+ val |= RTC7301_CONTROL_BANK_SEL_1;
+
+ rtc7301_update_bits(priv, RTC7301_CONTROL,
+ RTC7301_CONTROL_BANK_SEL_0 |
+ RTC7301_CONTROL_BANK_SEL_1, val);
+
+ priv->bank = bank;
+}
+
+static void rtc7301_get_time(struct rtc7301_priv *priv, struct rtc_time *tm,
+ bool alarm)
+{
+ int year;
+
+ tm->tm_sec = rtc7301_read(priv, RTC7301_1_SEC);
+ tm->tm_sec += (rtc7301_read(priv, RTC7301_10_SEC) & ~RTC7301_AE) * 10;
+ tm->tm_min = rtc7301_read(priv, RTC7301_1_MIN);
+ tm->tm_min += (rtc7301_read(priv, RTC7301_10_MIN) & ~RTC7301_AE) * 10;
+ tm->tm_hour = rtc7301_read(priv, RTC7301_1_HOUR);
+ tm->tm_hour += (rtc7301_read(priv, RTC7301_10_HOUR) & ~RTC7301_AE) * 10;
+ tm->tm_mday = rtc7301_read(priv, RTC7301_1_DAY);
+ tm->tm_mday += (rtc7301_read(priv, RTC7301_10_DAY) & ~RTC7301_AE) * 10;
+
+ if (alarm) {
+ tm->tm_wday = -1;
+ tm->tm_mon = -1;
+ tm->tm_year = -1;
+ tm->tm_yday = -1;
+ tm->tm_isdst = -1;
+ return;
+ }
+
+ tm->tm_wday = (rtc7301_read(priv, RTC7301_DAY_OF_WEEK) & ~RTC7301_AE);
+ tm->tm_mon = rtc7301_read(priv, RTC7301_10_MONTH) * 10 +
+ rtc7301_read(priv, RTC7301_1_MONTH) - 1;
+ year = rtc7301_read(priv, RTC7301_1000_YEAR) * 1000 +
+ rtc7301_read(priv, RTC7301_100_YEAR) * 100 +
+ rtc7301_read(priv, RTC7301_10_YEAR) * 10 +
+ rtc7301_read(priv, RTC7301_1_YEAR);
+
+ tm->tm_year = year - 1900;
+}
+
+static void rtc7301_write_time(struct rtc7301_priv *priv, struct rtc_time *tm,
+ bool alarm)
+{
+ int year;
+
+ rtc7301_write(priv, tm->tm_sec % 10, RTC7301_1_SEC);
+ rtc7301_write(priv, tm->tm_sec / 10, RTC7301_10_SEC);
+
+ rtc7301_write(priv, tm->tm_min % 10, RTC7301_1_MIN);
+ rtc7301_write(priv, tm->tm_min / 10, RTC7301_10_MIN);
+
+ rtc7301_write(priv, tm->tm_hour % 10, RTC7301_1_HOUR);
+ rtc7301_write(priv, tm->tm_hour / 10, RTC7301_10_HOUR);
+
+ rtc7301_write(priv, tm->tm_mday % 10, RTC7301_1_DAY);
+ rtc7301_write(priv, tm->tm_mday / 10, RTC7301_10_DAY);
+
+ /* Don't care for alarm register */
+ rtc7301_write(priv, alarm ? RTC7301_AE : tm->tm_wday,
+ RTC7301_DAY_OF_WEEK);
+
+ if (alarm)
+ return;
+
+ rtc7301_write(priv, (tm->tm_mon + 1) % 10, RTC7301_1_MONTH);
+ rtc7301_write(priv, (tm->tm_mon + 1) / 10, RTC7301_10_MONTH);
+
+ year = tm->tm_year + 1900;
+
+ rtc7301_write(priv, year % 10, RTC7301_1_YEAR);
+ rtc7301_write(priv, (year / 10) % 10, RTC7301_10_YEAR);
+ rtc7301_write(priv, (year / 100) % 10, RTC7301_100_YEAR);
+ rtc7301_write(priv, year / 1000, RTC7301_1000_YEAR);
+}
+
+static void rtc7301_alarm_irq(struct rtc7301_priv *priv, unsigned int enabled)
+{
+ rtc7301_update_bits(priv, RTC7301_ALARM_CONTROL,
+ RTC7301_ALARM_CONTROL_AF |
+ RTC7301_ALARM_CONTROL_AIE,
+ enabled ? RTC7301_ALARM_CONTROL_AIE : 0);
+}
+
+static int rtc7301_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rtc7301_priv *priv = dev_get_drvdata(dev);
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ rtc7301_select_bank(priv, 0);
+
+ err = rtc7301_wait_while_busy(priv);
+ if (!err)
+ rtc7301_get_time(priv, tm, false);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return err ? err : rtc_valid_tm(tm);
+}
+
+static int rtc7301_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rtc7301_priv *priv = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ rtc7301_stop(priv);
+ usleep_range(200, 300);
+ rtc7301_select_bank(priv, 0);
+ rtc7301_write_time(priv, tm, false);
+ rtc7301_start(priv);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int rtc7301_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct rtc7301_priv *priv = dev_get_drvdata(dev);
+ unsigned long flags;
+ u8 alrm_ctrl;
+
+ if (priv->irq <= 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ rtc7301_select_bank(priv, 1);
+ rtc7301_get_time(priv, &alarm->time, true);
+
+ alrm_ctrl = rtc7301_read(priv, RTC7301_ALARM_CONTROL);
+
+ alarm->enabled = !!(alrm_ctrl & RTC7301_ALARM_CONTROL_AIE);
+ alarm->pending = !!(alrm_ctrl & RTC7301_ALARM_CONTROL_AF);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int rtc7301_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct rtc7301_priv *priv = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ if (priv->irq <= 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ rtc7301_select_bank(priv, 1);
+ rtc7301_write_time(priv, &alarm->time, true);
+ rtc7301_alarm_irq(priv, alarm->enabled);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int rtc7301_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct rtc7301_priv *priv = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ if (priv->irq <= 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ rtc7301_select_bank(priv, 1);
+ rtc7301_alarm_irq(priv, enabled);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static const struct rtc_class_ops rtc7301_rtc_ops = {
+ .read_time = rtc7301_read_time,
+ .set_time = rtc7301_set_time,
+ .read_alarm = rtc7301_read_alarm,
+ .set_alarm = rtc7301_set_alarm,
+ .alarm_irq_enable = rtc7301_alarm_irq_enable,
+};
+
+static irqreturn_t rtc7301_irq_handler(int irq, void *dev_id)
+{
+ struct rtc_device *rtc = dev_id;
+ struct rtc7301_priv *priv = dev_get_drvdata(rtc->dev.parent);
+ unsigned long flags;
+ irqreturn_t ret = IRQ_NONE;
+ u8 alrm_ctrl;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ rtc7301_select_bank(priv, 1);
+
+ alrm_ctrl = rtc7301_read(priv, RTC7301_ALARM_CONTROL);
+ if (alrm_ctrl & RTC7301_ALARM_CONTROL_AF) {
+ ret = IRQ_HANDLED;
+ rtc7301_alarm_irq(priv, false);
+ rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return ret;
+}
+
+static void rtc7301_init(struct rtc7301_priv *priv)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ rtc7301_select_bank(priv, 2);
+ rtc7301_write(priv, 0, RTC7301_TIMER_CONTROL);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int __init rtc7301_rtc_probe(struct platform_device *dev)
+{
+ struct resource *res;
+ void __iomem *regs;
+ struct rtc7301_priv *priv;
+ struct rtc_device *rtc;
+ int ret;
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ regs = devm_ioremap_resource(&dev->dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ priv->regmap = devm_regmap_init_mmio(&dev->dev, regs,
+ &rtc7301_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ priv->irq = platform_get_irq(dev, 0);
+
+ spin_lock_init(&priv->lock);
+ priv->bank = -1;
+
+ rtc7301_init(priv);
+
+ platform_set_drvdata(dev, priv);
+
+ rtc = devm_rtc_device_register(&dev->dev, DRV_NAME, &rtc7301_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ if (priv->irq > 0) {
+ ret = devm_request_irq(&dev->dev, priv->irq,
+ rtc7301_irq_handler, IRQF_SHARED,
+ dev_name(&dev->dev), rtc);
+ if (ret) {
+ priv->irq = 0;
+ dev_err(&dev->dev, "unable to request IRQ\n");
+ } else {
+ device_set_wakeup_capable(&dev->dev, true);
+ }
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int rtc7301_suspend(struct device *dev)
+{
+ struct rtc7301_priv *priv = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(priv->irq);
+
+ return 0;
+}
+
+static int rtc7301_resume(struct device *dev)
+{
+ struct rtc7301_priv *priv = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(priv->irq);
+
+ return 0;
+}
+
+#endif
+
+static SIMPLE_DEV_PM_OPS(rtc7301_pm_ops, rtc7301_suspend, rtc7301_resume);
+
+static const struct of_device_id rtc7301_dt_match[] = {
+ { .compatible = "epson,rtc7301sf" },
+ { .compatible = "epson,rtc7301dg" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rtc7301_dt_match);
+
+static struct platform_driver rtc7301_rtc_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = rtc7301_dt_match,
+ .pm = &rtc7301_pm_ops,
+ },
+};
+
+module_platform_driver_probe(rtc7301_rtc_driver, rtc7301_rtc_probe);
+
+MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EPSON TOYOCOM RTC-7301SF/DG Driver");
+MODULE_ALIAS("platform:rtc-r7301");
diff --git a/drivers/rtc/rtc-starfire.c b/drivers/rtc/rtc-starfire.c
index 83a057a03060..7fc36973fa33 100644
--- a/drivers/rtc/rtc-starfire.c
+++ b/drivers/rtc/rtc-starfire.c
@@ -1,20 +1,18 @@
/* rtc-starfire.c: Starfire platform RTC driver.
*
+ * Author: David S. Miller
+ * License: GPL
+ *
* Copyright (C) 2008 David S. Miller <davem@davemloft.net>
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <asm/oplib.h>
-MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
-MODULE_DESCRIPTION("Starfire RTC driver");
-MODULE_LICENSE("GPL");
-
static u32 starfire_get_time(void)
{
static char obp_gettod[32];
@@ -57,4 +55,4 @@ static struct platform_driver starfire_rtc_driver = {
},
};
-module_platform_driver_probe(starfire_rtc_driver, starfire_rtc_probe);
+builtin_platform_driver_probe(starfire_rtc_driver, starfire_rtc_probe);
diff --git a/drivers/rtc/rtc-sun4v.c b/drivers/rtc/rtc-sun4v.c
index 7c696c12f28f..11bc562eba5d 100644
--- a/drivers/rtc/rtc-sun4v.c
+++ b/drivers/rtc/rtc-sun4v.c
@@ -1,12 +1,14 @@
/* rtc-sun4v.c: Hypervisor based RTC for SUN4V systems.
*
+ * Author: David S. Miller
+ * License: GPL
+ *
* Copyright (C) 2008 David S. Miller <davem@davemloft.net>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/rtc.h>
@@ -98,8 +100,4 @@ static struct platform_driver sun4v_rtc_driver = {
},
};
-module_platform_driver_probe(sun4v_rtc_driver, sun4v_rtc_probe);
-
-MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
-MODULE_DESCRIPTION("SUN4V RTC driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver_probe(sun4v_rtc_driver, sun4v_rtc_probe);
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
index 176720b7b9e5..c18c39212ce6 100644
--- a/drivers/rtc/rtc-twl.c
+++ b/drivers/rtc/rtc-twl.c
@@ -33,6 +33,10 @@
#include <linux/i2c/twl.h>
+enum twl_class {
+ TWL_4030 = 0,
+ TWL_6030,
+};
/*
* RTC block register offsets (use TWL_MODULE_RTC)
@@ -136,16 +140,30 @@ static const u8 twl6030_rtc_reg_map[] = {
#define ALL_TIME_REGS 6
/*----------------------------------------------------------------------*/
-static u8 *rtc_reg_map;
+struct twl_rtc {
+ struct device *dev;
+ struct rtc_device *rtc;
+ u8 *reg_map;
+ /*
+ * Cache the value for timer/alarm interrupts register; this is
+ * only changed by callers holding rtc ops lock (or resume).
+ */
+ unsigned char rtc_irq_bits;
+ bool wake_enabled;
+#ifdef CONFIG_PM_SLEEP
+ unsigned char irqstat;
+#endif
+ enum twl_class class;
+};
/*
* Supports 1 byte read from TWL RTC register.
*/
-static int twl_rtc_read_u8(u8 *data, u8 reg)
+static int twl_rtc_read_u8(struct twl_rtc *twl_rtc, u8 *data, u8 reg)
{
int ret;
- ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg]));
+ ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (twl_rtc->reg_map[reg]));
if (ret < 0)
pr_err("Could not read TWL register %X - error %d\n", reg, ret);
return ret;
@@ -154,11 +172,11 @@ static int twl_rtc_read_u8(u8 *data, u8 reg)
/*
* Supports 1 byte write to TWL RTC registers.
*/
-static int twl_rtc_write_u8(u8 data, u8 reg)
+static int twl_rtc_write_u8(struct twl_rtc *twl_rtc, u8 data, u8 reg)
{
int ret;
- ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg]));
+ ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (twl_rtc->reg_map[reg]));
if (ret < 0)
pr_err("Could not write TWL register %X - error %d\n",
reg, ret);
@@ -166,28 +184,22 @@ static int twl_rtc_write_u8(u8 data, u8 reg)
}
/*
- * Cache the value for timer/alarm interrupts register; this is
- * only changed by callers holding rtc ops lock (or resume).
- */
-static unsigned char rtc_irq_bits;
-
-/*
* Enable 1/second update and/or alarm interrupts.
*/
-static int set_rtc_irq_bit(unsigned char bit)
+static int set_rtc_irq_bit(struct twl_rtc *twl_rtc, unsigned char bit)
{
unsigned char val;
int ret;
/* if the bit is set, return from here */
- if (rtc_irq_bits & bit)
+ if (twl_rtc->rtc_irq_bits & bit)
return 0;
- val = rtc_irq_bits | bit;
+ val = twl_rtc->rtc_irq_bits | bit;
val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M;
- ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
+ ret = twl_rtc_write_u8(twl_rtc, val, REG_RTC_INTERRUPTS_REG);
if (ret == 0)
- rtc_irq_bits = val;
+ twl_rtc->rtc_irq_bits = val;
return ret;
}
@@ -195,19 +207,19 @@ static int set_rtc_irq_bit(unsigned char bit)
/*
* Disable update and/or alarm interrupts.
*/
-static int mask_rtc_irq_bit(unsigned char bit)
+static int mask_rtc_irq_bit(struct twl_rtc *twl_rtc, unsigned char bit)
{
unsigned char val;
int ret;
/* if the bit is clear, return from here */
- if (!(rtc_irq_bits & bit))
+ if (!(twl_rtc->rtc_irq_bits & bit))
return 0;
- val = rtc_irq_bits & ~bit;
- ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
+ val = twl_rtc->rtc_irq_bits & ~bit;
+ ret = twl_rtc_write_u8(twl_rtc, val, REG_RTC_INTERRUPTS_REG);
if (ret == 0)
- rtc_irq_bits = val;
+ twl_rtc->rtc_irq_bits = val;
return ret;
}
@@ -215,21 +227,23 @@ static int mask_rtc_irq_bit(unsigned char bit)
static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
{
struct platform_device *pdev = to_platform_device(dev);
+ struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
int irq = platform_get_irq(pdev, 0);
- static bool twl_rtc_wake_enabled;
int ret;
if (enabled) {
- ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
- if (device_can_wakeup(dev) && !twl_rtc_wake_enabled) {
+ ret = set_rtc_irq_bit(twl_rtc,
+ BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+ if (device_can_wakeup(dev) && !twl_rtc->wake_enabled) {
enable_irq_wake(irq);
- twl_rtc_wake_enabled = true;
+ twl_rtc->wake_enabled = true;
}
} else {
- ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
- if (twl_rtc_wake_enabled) {
+ ret = mask_rtc_irq_bit(twl_rtc,
+ BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+ if (twl_rtc->wake_enabled) {
disable_irq_wake(irq);
- twl_rtc_wake_enabled = false;
+ twl_rtc->wake_enabled = false;
}
}
@@ -247,21 +261,23 @@ static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
*/
static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
+ struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
unsigned char rtc_data[ALL_TIME_REGS];
int ret;
u8 save_control;
u8 rtc_control;
- ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
+ ret = twl_rtc_read_u8(twl_rtc, &save_control, REG_RTC_CTRL_REG);
if (ret < 0) {
dev_err(dev, "%s: reading CTRL_REG, error %d\n", __func__, ret);
return ret;
}
/* for twl6030/32 make sure BIT_RTC_CTRL_REG_GET_TIME_M is clear */
- if (twl_class_is_6030()) {
+ if (twl_rtc->class == TWL_6030) {
if (save_control & BIT_RTC_CTRL_REG_GET_TIME_M) {
save_control &= ~BIT_RTC_CTRL_REG_GET_TIME_M;
- ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+ ret = twl_rtc_write_u8(twl_rtc, save_control,
+ REG_RTC_CTRL_REG);
if (ret < 0) {
dev_err(dev, "%s clr GET_TIME, error %d\n",
__func__, ret);
@@ -274,17 +290,17 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
rtc_control = save_control | BIT_RTC_CTRL_REG_GET_TIME_M;
/* for twl6030/32 enable read access to static shadowed registers */
- if (twl_class_is_6030())
+ if (twl_rtc->class == TWL_6030)
rtc_control |= BIT_RTC_CTRL_REG_RTC_V_OPT;
- ret = twl_rtc_write_u8(rtc_control, REG_RTC_CTRL_REG);
+ ret = twl_rtc_write_u8(twl_rtc, rtc_control, REG_RTC_CTRL_REG);
if (ret < 0) {
dev_err(dev, "%s: writing CTRL_REG, error %d\n", __func__, ret);
return ret;
}
ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
- (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
+ (twl_rtc->reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
if (ret < 0) {
dev_err(dev, "%s: reading data, error %d\n", __func__, ret);
@@ -292,8 +308,8 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
}
/* for twl6030 restore original state of rtc control register */
- if (twl_class_is_6030()) {
- ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+ if (twl_rtc->class == TWL_6030) {
+ ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
if (ret < 0) {
dev_err(dev, "%s: restore CTRL_REG, error %d\n",
__func__, ret);
@@ -313,6 +329,7 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
+ struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
unsigned char save_control;
unsigned char rtc_data[ALL_TIME_REGS];
int ret;
@@ -325,18 +342,18 @@ static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
rtc_data[5] = bin2bcd(tm->tm_year - 100);
/* Stop RTC while updating the TC registers */
- ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
+ ret = twl_rtc_read_u8(twl_rtc, &save_control, REG_RTC_CTRL_REG);
if (ret < 0)
goto out;
save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M;
- ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+ ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
if (ret < 0)
goto out;
/* update all the time registers in one shot */
ret = twl_i2c_write(TWL_MODULE_RTC, rtc_data,
- (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
+ (twl_rtc->reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
if (ret < 0) {
dev_err(dev, "rtc_set_time error %d\n", ret);
goto out;
@@ -344,7 +361,7 @@ static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
/* Start back RTC */
save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M;
- ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+ ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
out:
return ret;
@@ -355,11 +372,12 @@ out:
*/
static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
+ struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
unsigned char rtc_data[ALL_TIME_REGS];
int ret;
ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
- (rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS);
+ twl_rtc->reg_map[REG_ALARM_SECONDS_REG], ALL_TIME_REGS);
if (ret < 0) {
dev_err(dev, "rtc_read_alarm error %d\n", ret);
return ret;
@@ -374,7 +392,7 @@ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
alm->time.tm_year = bcd2bin(rtc_data[5]) + 100;
/* report cached alarm enable state */
- if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
+ if (twl_rtc->rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
alm->enabled = 1;
return ret;
@@ -382,6 +400,8 @@ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
+ struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
+
unsigned char alarm_data[ALL_TIME_REGS];
int ret;
@@ -398,7 +418,7 @@ static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
/* update all the alarm registers in one shot */
ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data,
- (rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS);
+ twl_rtc->reg_map[REG_ALARM_SECONDS_REG], ALL_TIME_REGS);
if (ret) {
dev_err(dev, "rtc_set_alarm error %d\n", ret);
goto out;
@@ -410,14 +430,15 @@ out:
return ret;
}
-static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
+static irqreturn_t twl_rtc_interrupt(int irq, void *data)
{
+ struct twl_rtc *twl_rtc = data;
unsigned long events;
int ret = IRQ_NONE;
int res;
u8 rd_reg;
- res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
+ res = twl_rtc_read_u8(twl_rtc, &rd_reg, REG_RTC_STATUS_REG);
if (res)
goto out;
/*
@@ -431,12 +452,12 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
else
events = RTC_IRQF | RTC_PF;
- res = twl_rtc_write_u8(BIT_RTC_STATUS_REG_ALARM_M,
- REG_RTC_STATUS_REG);
+ res = twl_rtc_write_u8(twl_rtc, BIT_RTC_STATUS_REG_ALARM_M,
+ REG_RTC_STATUS_REG);
if (res)
goto out;
- if (twl_class_is_4030()) {
+ if (twl_rtc->class == TWL_4030) {
/* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1
* needs 2 reads to clear the interrupt. One read is done in
* do_twl_pwrirq(). Doing the second read, to clear
@@ -455,7 +476,7 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
}
/* Notify RTC core on event */
- rtc_update_irq(rtc, 1, events);
+ rtc_update_irq(twl_rtc->rtc, 1, events);
ret = IRQ_HANDLED;
out:
@@ -474,21 +495,36 @@ static const struct rtc_class_ops twl_rtc_ops = {
static int twl_rtc_probe(struct platform_device *pdev)
{
- struct rtc_device *rtc;
+ struct twl_rtc *twl_rtc;
+ struct device_node *np = pdev->dev.of_node;
int ret = -EINVAL;
int irq = platform_get_irq(pdev, 0);
u8 rd_reg;
+ if (!np) {
+ dev_err(&pdev->dev, "no DT info\n");
+ return -EINVAL;
+ }
+
if (irq <= 0)
return ret;
- /* Initialize the register map */
- if (twl_class_is_4030())
- rtc_reg_map = (u8 *)twl4030_rtc_reg_map;
- else
- rtc_reg_map = (u8 *)twl6030_rtc_reg_map;
+ twl_rtc = devm_kzalloc(&pdev->dev, sizeof(*twl_rtc), GFP_KERNEL);
+ if (!twl_rtc)
+ return -ENOMEM;
- ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
+ if (twl_class_is_4030()) {
+ twl_rtc->class = TWL_4030;
+ twl_rtc->reg_map = (u8 *)twl4030_rtc_reg_map;
+ } else if (twl_class_is_6030()) {
+ twl_rtc->class = TWL_6030;
+ twl_rtc->reg_map = (u8 *)twl6030_rtc_reg_map;
+ } else {
+ dev_err(&pdev->dev, "TWL Class not supported.\n");
+ return -EINVAL;
+ }
+
+ ret = twl_rtc_read_u8(twl_rtc, &rd_reg, REG_RTC_STATUS_REG);
if (ret < 0)
return ret;
@@ -499,11 +535,11 @@ static int twl_rtc_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n");
/* Clear RTC Power up reset and pending alarm interrupts */
- ret = twl_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG);
+ ret = twl_rtc_write_u8(twl_rtc, rd_reg, REG_RTC_STATUS_REG);
if (ret < 0)
return ret;
- if (twl_class_is_6030()) {
+ if (twl_rtc->class == TWL_6030) {
twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
REG_INT_MSK_LINE_A);
twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
@@ -511,40 +547,42 @@ static int twl_rtc_probe(struct platform_device *pdev)
}
dev_info(&pdev->dev, "Enabling TWL-RTC\n");
- ret = twl_rtc_write_u8(BIT_RTC_CTRL_REG_STOP_RTC_M, REG_RTC_CTRL_REG);
+ ret = twl_rtc_write_u8(twl_rtc, BIT_RTC_CTRL_REG_STOP_RTC_M,
+ REG_RTC_CTRL_REG);
if (ret < 0)
return ret;
/* ensure interrupts are disabled, bootloaders can be strange */
- ret = twl_rtc_write_u8(0, REG_RTC_INTERRUPTS_REG);
+ ret = twl_rtc_write_u8(twl_rtc, 0, REG_RTC_INTERRUPTS_REG);
if (ret < 0)
dev_warn(&pdev->dev, "unable to disable interrupt\n");
/* init cached IRQ enable bits */
- ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);
+ ret = twl_rtc_read_u8(twl_rtc, &twl_rtc->rtc_irq_bits,
+ REG_RTC_INTERRUPTS_REG);
if (ret < 0)
return ret;
+ platform_set_drvdata(pdev, twl_rtc);
device_init_wakeup(&pdev->dev, 1);
- rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ twl_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&twl_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc)) {
+ if (IS_ERR(twl_rtc->rtc)) {
dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
- PTR_ERR(rtc));
- return PTR_ERR(rtc);
+ PTR_ERR(twl_rtc->rtc));
+ return PTR_ERR(twl_rtc->rtc);
}
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
twl_rtc_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
- dev_name(&rtc->dev), rtc);
+ dev_name(&twl_rtc->rtc->dev), twl_rtc);
if (ret < 0) {
dev_err(&pdev->dev, "IRQ is not free.\n");
return ret;
}
- platform_set_drvdata(pdev, rtc);
return 0;
}
@@ -554,10 +592,12 @@ static int twl_rtc_probe(struct platform_device *pdev)
*/
static int twl_rtc_remove(struct platform_device *pdev)
{
+ struct twl_rtc *twl_rtc = platform_get_drvdata(pdev);
+
/* leave rtc running, but disable irqs */
- mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
- mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
- if (twl_class_is_6030()) {
+ mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+ mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+ if (twl_rtc->class == TWL_6030) {
twl6030_interrupt_mask(TWL6030_RTC_INT_MASK,
REG_INT_MSK_LINE_A);
twl6030_interrupt_mask(TWL6030_RTC_INT_MASK,
@@ -569,40 +609,40 @@ static int twl_rtc_remove(struct platform_device *pdev)
static void twl_rtc_shutdown(struct platform_device *pdev)
{
+ struct twl_rtc *twl_rtc = platform_get_drvdata(pdev);
+
/* mask timer interrupts, but leave alarm interrupts on to enable
power-on when alarm is triggered */
- mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+ mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
}
#ifdef CONFIG_PM_SLEEP
-static unsigned char irqstat;
-
static int twl_rtc_suspend(struct device *dev)
{
- irqstat = rtc_irq_bits;
+ struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
+
+ twl_rtc->irqstat = twl_rtc->rtc_irq_bits;
- mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+ mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
return 0;
}
static int twl_rtc_resume(struct device *dev)
{
- set_rtc_irq_bit(irqstat);
+ struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
+
+ set_rtc_irq_bit(twl_rtc, twl_rtc->irqstat);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(twl_rtc_pm_ops, twl_rtc_suspend, twl_rtc_resume);
-#ifdef CONFIG_OF
static const struct of_device_id twl_rtc_of_match[] = {
{.compatible = "ti,twl4030-rtc", },
{ },
};
MODULE_DEVICE_TABLE(of, twl_rtc_of_match);
-#endif
-
-MODULE_ALIAS("platform:twl_rtc");
static struct platform_driver twl4030rtc_driver = {
.probe = twl_rtc_probe,
@@ -611,7 +651,7 @@ static struct platform_driver twl4030rtc_driver = {
.driver = {
.name = "twl_rtc",
.pm = &twl_rtc_pm_ops,
- .of_match_table = of_match_ptr(twl_rtc_of_match),
+ .of_match_table = twl_rtc_of_match,
},
};
diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
index c9fa3565c671..2583e8b50b21 100644
--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
+++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
@@ -30,6 +30,7 @@
#include <linux/types.h>
#include <linux/list.h>
#include <linux/string.h>
+#include <linux/delay.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
index 98b0ca79a5c5..65c6189885ab 100644
--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
+++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
@@ -26,6 +26,7 @@
#ifndef __H_IBMVSCSI_TGT
#define __H_IBMVSCSI_TGT
+#include <linux/interrupt.h>
#include "libsrp.h"
#define SYS_ID_NAME_LEN 64
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 19f18485a854..d8efddf6f312 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -9,6 +9,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/t10-pi.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_bsg_fc.h>
#include <scsi/scsi_eh.h>
diff --git a/drivers/staging/lustre/lustre/llite/symlink.c b/drivers/staging/lustre/lustre/llite/symlink.c
index 82c7c48aa619..cd77b55d3895 100644
--- a/drivers/staging/lustre/lustre/llite/symlink.c
+++ b/drivers/staging/lustre/lustre/llite/symlink.c
@@ -149,7 +149,6 @@ static const char *ll_get_link(struct dentry *dentry,
}
const struct inode_operations ll_fast_symlink_inode_operations = {
- .readlink = generic_readlink,
.setattr = ll_setattr,
.get_link = ll_get_link,
.getattr = ll_getattr,
diff --git a/drivers/target/iscsi/cxgbit/cxgbit_target.c b/drivers/target/iscsi/cxgbit/cxgbit_target.c
index d02bf58aea6d..8bcb9b71f764 100644
--- a/drivers/target/iscsi/cxgbit/cxgbit_target.c
+++ b/drivers/target/iscsi/cxgbit/cxgbit_target.c
@@ -9,6 +9,7 @@
#include <linux/workqueue.h>
#include <linux/kthread.h>
#include <asm/unaligned.h>
+#include <net/tcp.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
#include "cxgbit.h"
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index b7d747e92c7a..da2c73a255de 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -23,7 +23,9 @@
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/idr.h>
+#include <linux/delay.h>
#include <asm/unaligned.h>
+#include <net/ipv6.h>
#include <scsi/scsi_proto.h>
#include <scsi/iscsi_proto.h>
#include <scsi/scsi_tcq.h>
diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h
index 4cf2c0f2ba2f..e0db2ceb0f87 100644
--- a/drivers/target/iscsi/iscsi_target.h
+++ b/drivers/target/iscsi/iscsi_target.h
@@ -1,6 +1,18 @@
#ifndef ISCSI_TARGET_H
#define ISCSI_TARGET_H
+#include <linux/types.h>
+#include <linux/spinlock.h>
+
+struct iscsi_cmd;
+struct iscsi_conn;
+struct iscsi_np;
+struct iscsi_portal_group;
+struct iscsi_session;
+struct iscsi_tpg_np;
+struct kref;
+struct sockaddr_storage;
+
extern struct iscsi_tiqn *iscsit_get_tiqn_for_login(unsigned char *);
extern struct iscsi_tiqn *iscsit_get_tiqn(unsigned char *, int);
extern void iscsit_put_tiqn_for_login(struct iscsi_tiqn *);
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c
index e116f0e845c0..903b667f8e01 100644
--- a/drivers/target/iscsi/iscsi_target_auth.c
+++ b/drivers/target/iscsi/iscsi_target_auth.c
@@ -20,8 +20,8 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/err.h>
+#include <linux/random.h>
#include <linux/scatterlist.h>
-
#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_nego.h"
#include "iscsi_target_auth.h"
diff --git a/drivers/target/iscsi/iscsi_target_auth.h b/drivers/target/iscsi/iscsi_target_auth.h
index d22f7b96a06c..1b91c13cc965 100644
--- a/drivers/target/iscsi/iscsi_target_auth.h
+++ b/drivers/target/iscsi/iscsi_target_auth.h
@@ -1,6 +1,8 @@
#ifndef _ISCSI_CHAP_H_
#define _ISCSI_CHAP_H_
+#include <linux/types.h>
+
#define CHAP_DIGEST_UNKNOWN 0
#define CHAP_DIGEST_MD5 5
#define CHAP_DIGEST_SHA 6
@@ -18,6 +20,9 @@
#define CHAP_STAGE_CLIENT_NRIC 4
#define CHAP_STAGE_SERVER_NR 5
+struct iscsi_node_auth;
+struct iscsi_conn;
+
extern u32 chap_main_loop(struct iscsi_conn *, struct iscsi_node_auth *, char *, char *,
int *, int *);
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index 923c032f0b95..bf40f03755dd 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -21,10 +21,11 @@
#include <linux/ctype.h>
#include <linux/export.h>
#include <linux/inet.h>
+#include <linux/module.h>
+#include <net/ipv6.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
#include <target/iscsi/iscsi_transport.h>
-
#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_parameters.h"
#include "iscsi_target_device.h"
@@ -100,8 +101,10 @@ static ssize_t lio_target_np_driver_store(struct config_item *item,
tpg_np_new = iscsit_tpg_add_network_portal(tpg,
&np->np_sockaddr, tpg_np, type);
- if (IS_ERR(tpg_np_new))
+ if (IS_ERR(tpg_np_new)) {
+ rc = PTR_ERR(tpg_np_new);
goto out;
+ }
} else {
tpg_np_new = iscsit_tpg_locate_child_np(tpg_np, type);
if (tpg_np_new) {
diff --git a/drivers/target/iscsi/iscsi_target_datain_values.c b/drivers/target/iscsi/iscsi_target_datain_values.c
index 647d4a5dca52..173ddd93c757 100644
--- a/drivers/target/iscsi/iscsi_target_datain_values.c
+++ b/drivers/target/iscsi/iscsi_target_datain_values.c
@@ -16,8 +16,8 @@
* GNU General Public License for more details.
******************************************************************************/
+#include <linux/slab.h>
#include <scsi/iscsi_proto.h>
-
#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_seq_pdu_list.h"
#include "iscsi_target_erl1.h"
diff --git a/drivers/target/iscsi/iscsi_target_datain_values.h b/drivers/target/iscsi/iscsi_target_datain_values.h
index 646429ac5a02..16edeeeb7777 100644
--- a/drivers/target/iscsi/iscsi_target_datain_values.h
+++ b/drivers/target/iscsi/iscsi_target_datain_values.h
@@ -1,6 +1,9 @@
#ifndef ISCSI_TARGET_DATAIN_VALUES_H
#define ISCSI_TARGET_DATAIN_VALUES_H
+struct iscsi_cmd;
+struct iscsi_datain;
+
extern struct iscsi_datain_req *iscsit_allocate_datain_req(void);
extern void iscsit_attach_datain_req(struct iscsi_cmd *, struct iscsi_datain_req *);
extern void iscsit_free_datain_req(struct iscsi_cmd *, struct iscsi_datain_req *);
diff --git a/drivers/target/iscsi/iscsi_target_device.h b/drivers/target/iscsi/iscsi_target_device.h
index a0e2df9e8090..06dbff5cd520 100644
--- a/drivers/target/iscsi/iscsi_target_device.h
+++ b/drivers/target/iscsi/iscsi_target_device.h
@@ -1,6 +1,9 @@
#ifndef ISCSI_TARGET_DEVICE_H
#define ISCSI_TARGET_DEVICE_H
+struct iscsi_cmd;
+struct iscsi_session;
+
extern void iscsit_determine_maxcmdsn(struct iscsi_session *);
extern void iscsit_increment_maxcmdsn(struct iscsi_cmd *, struct iscsi_session *);
diff --git a/drivers/target/iscsi/iscsi_target_erl0.h b/drivers/target/iscsi/iscsi_target_erl0.h
index a9e2f9497fb2..60e69e2af6ed 100644
--- a/drivers/target/iscsi/iscsi_target_erl0.h
+++ b/drivers/target/iscsi/iscsi_target_erl0.h
@@ -1,6 +1,12 @@
#ifndef ISCSI_TARGET_ERL0_H
#define ISCSI_TARGET_ERL0_H
+#include <linux/types.h>
+
+struct iscsi_cmd;
+struct iscsi_conn;
+struct iscsi_session;
+
extern void iscsit_set_dataout_sequence_values(struct iscsi_cmd *);
extern int iscsit_check_pre_dataout(struct iscsi_cmd *, unsigned char *);
extern int iscsit_check_post_dataout(struct iscsi_cmd *, unsigned char *, u8);
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c
index 9214c9dafa2b..fe9b7f1e44ac 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.c
+++ b/drivers/target/iscsi/iscsi_target_erl1.c
@@ -17,6 +17,7 @@
******************************************************************************/
#include <linux/list.h>
+#include <linux/slab.h>
#include <scsi/iscsi_proto.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
diff --git a/drivers/target/iscsi/iscsi_target_erl1.h b/drivers/target/iscsi/iscsi_target_erl1.h
index 2a3ebf118a34..54d36bd25bea 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.h
+++ b/drivers/target/iscsi/iscsi_target_erl1.h
@@ -1,6 +1,16 @@
#ifndef ISCSI_TARGET_ERL1_H
#define ISCSI_TARGET_ERL1_H
+#include <linux/types.h>
+#include <scsi/iscsi_proto.h> /* itt_t */
+
+struct iscsi_cmd;
+struct iscsi_conn;
+struct iscsi_datain_req;
+struct iscsi_ooo_cmdsn;
+struct iscsi_pdu;
+struct iscsi_session;
+
extern int iscsit_dump_data_payload(struct iscsi_conn *, u32, int);
extern int iscsit_create_recovery_datain_values_datasequenceinorder_yes(
struct iscsi_cmd *, struct iscsi_datain_req *);
diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c
index e24f1c7c5862..faf9ae014b30 100644
--- a/drivers/target/iscsi/iscsi_target_erl2.c
+++ b/drivers/target/iscsi/iscsi_target_erl2.c
@@ -17,6 +17,7 @@
* GNU General Public License for more details.
******************************************************************************/
+#include <linux/slab.h>
#include <scsi/iscsi_proto.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
diff --git a/drivers/target/iscsi/iscsi_target_erl2.h b/drivers/target/iscsi/iscsi_target_erl2.h
index 63f2501f3fe0..7965f1e86506 100644
--- a/drivers/target/iscsi/iscsi_target_erl2.h
+++ b/drivers/target/iscsi/iscsi_target_erl2.h
@@ -1,6 +1,13 @@
#ifndef ISCSI_TARGET_ERL2_H
#define ISCSI_TARGET_ERL2_H
+#include <linux/types.h>
+
+struct iscsi_cmd;
+struct iscsi_conn;
+struct iscsi_conn_recovery;
+struct iscsi_session;
+
extern void iscsit_create_conn_recovery_datain_values(struct iscsi_cmd *, __be32);
extern void iscsit_create_conn_recovery_dataout_values(struct iscsi_cmd *);
extern struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry(
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index 15f79a2ca34a..450f51deb2a2 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -20,6 +20,8 @@
#include <linux/string.h>
#include <linux/kthread.h>
#include <linux/idr.h>
+#include <linux/tcp.h> /* TCP_NODELAY */
+#include <net/ipv6.h> /* ipv6_addr_v4mapped() */
#include <scsi/iscsi_proto.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
diff --git a/drivers/target/iscsi/iscsi_target_login.h b/drivers/target/iscsi/iscsi_target_login.h
index b597aa2c61a1..0e1fd6cedd54 100644
--- a/drivers/target/iscsi/iscsi_target_login.h
+++ b/drivers/target/iscsi/iscsi_target_login.h
@@ -1,6 +1,13 @@
#ifndef ISCSI_TARGET_LOGIN_H
#define ISCSI_TARGET_LOGIN_H
+#include <linux/types.h>
+
+struct iscsi_conn;
+struct iscsi_login;
+struct iscsi_np;
+struct sockaddr_storage;
+
extern int iscsi_login_setup_crypto(struct iscsi_conn *);
extern int iscsi_check_for_session_reinstatement(struct iscsi_conn *);
extern int iscsi_login_post_auth_non_zero_tsih(struct iscsi_conn *, u16, u32);
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index 89d34bd6d87f..46388c9e08da 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -18,6 +18,8 @@
#include <linux/ctype.h>
#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <net/sock.h>
#include <scsi/iscsi_proto.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
diff --git a/drivers/target/iscsi/iscsi_target_nego.h b/drivers/target/iscsi/iscsi_target_nego.h
index f021cbd330e5..53438bfca4c6 100644
--- a/drivers/target/iscsi/iscsi_target_nego.h
+++ b/drivers/target/iscsi/iscsi_target_nego.h
@@ -4,6 +4,10 @@
#define DECIMAL 0
#define HEX 1
+struct iscsi_conn;
+struct iscsi_login;
+struct iscsi_np;
+
extern void convert_null_to_semi(char *, int);
extern int extract_param(const char *, const char *, unsigned int, char *,
unsigned char *);
diff --git a/drivers/target/iscsi/iscsi_target_nodeattrib.h b/drivers/target/iscsi/iscsi_target_nodeattrib.h
index 0c69a46a62ec..79cdf06ade48 100644
--- a/drivers/target/iscsi/iscsi_target_nodeattrib.h
+++ b/drivers/target/iscsi/iscsi_target_nodeattrib.h
@@ -1,6 +1,11 @@
#ifndef ISCSI_TARGET_NODEATTRIB_H
#define ISCSI_TARGET_NODEATTRIB_H
+#include <linux/types.h>
+
+struct iscsi_node_acl;
+struct iscsi_portal_group;
+
extern void iscsit_set_default_node_attribues(struct iscsi_node_acl *,
struct iscsi_portal_group *);
extern int iscsit_na_dataout_timeout(struct iscsi_node_acl *, u32);
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index 0efa80bb8962..e65bf78ceef3 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -17,7 +17,7 @@
******************************************************************************/
#include <linux/slab.h>
-
+#include <linux/uio.h> /* struct kvec */
#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_util.h"
#include "iscsi_target_parameters.h"
diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h
index a0751e3f0813..9962ccf0ccd7 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.h
+++ b/drivers/target/iscsi/iscsi_target_parameters.h
@@ -1,6 +1,7 @@
#ifndef ISCSI_PARAMETERS_H
#define ISCSI_PARAMETERS_H
+#include <linux/types.h>
#include <scsi/iscsi_proto.h>
struct iscsi_extra_response {
@@ -23,6 +24,11 @@ struct iscsi_param {
struct list_head p_list;
} ____cacheline_aligned;
+struct iscsi_conn;
+struct iscsi_conn_ops;
+struct iscsi_param_list;
+struct iscsi_sess_ops;
+
extern int iscsi_login_rx_data(struct iscsi_conn *, char *, int);
extern int iscsi_login_tx_data(struct iscsi_conn *, char *, char *, int);
extern void iscsi_dump_conn_ops(struct iscsi_conn_ops *);
diff --git a/drivers/target/iscsi/iscsi_target_seq_pdu_list.h b/drivers/target/iscsi/iscsi_target_seq_pdu_list.h
index d5b153751a8d..be1234362271 100644
--- a/drivers/target/iscsi/iscsi_target_seq_pdu_list.h
+++ b/drivers/target/iscsi/iscsi_target_seq_pdu_list.h
@@ -1,6 +1,9 @@
#ifndef ISCSI_SEQ_AND_PDU_LIST_H
#define ISCSI_SEQ_AND_PDU_LIST_H
+#include <linux/types.h>
+#include <linux/cache.h>
+
/* struct iscsi_pdu->status */
#define DATAOUT_PDU_SENT 1
@@ -78,6 +81,8 @@ struct iscsi_seq {
u32 xfer_len;
} ____cacheline_aligned;
+struct iscsi_cmd;
+
extern int iscsit_build_pdu_and_seq_lists(struct iscsi_cmd *, u32);
extern struct iscsi_pdu *iscsit_get_pdu_holder(struct iscsi_cmd *, u32, u32);
extern struct iscsi_pdu *iscsit_get_pdu_holder_for_seq(struct iscsi_cmd *, struct iscsi_seq *);
diff --git a/drivers/target/iscsi/iscsi_target_tmr.h b/drivers/target/iscsi/iscsi_target_tmr.h
index 142e992cb097..64cc5c07e47c 100644
--- a/drivers/target/iscsi/iscsi_target_tmr.h
+++ b/drivers/target/iscsi/iscsi_target_tmr.h
@@ -1,6 +1,12 @@
#ifndef ISCSI_TARGET_TMR_H
#define ISCSI_TARGET_TMR_H
+#include <linux/types.h>
+
+struct iscsi_cmd;
+struct iscsi_conn;
+struct iscsi_tmr_req;
+
extern u8 iscsit_tmr_abort_task(struct iscsi_cmd *, unsigned char *);
extern int iscsit_tmr_task_warm_reset(struct iscsi_conn *, struct iscsi_tmr_req *,
unsigned char *);
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c
index 0814e5894a96..2e7e08dbda48 100644
--- a/drivers/target/iscsi/iscsi_target_tpg.c
+++ b/drivers/target/iscsi/iscsi_target_tpg.c
@@ -16,9 +16,9 @@
* GNU General Public License for more details.
******************************************************************************/
+#include <linux/slab.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-
#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_erl0.h"
#include "iscsi_target_login.h"
@@ -260,7 +260,6 @@ err_out:
iscsi_release_param_list(tpg->param_list);
tpg->param_list = NULL;
}
- kfree(tpg);
return -ENOMEM;
}
diff --git a/drivers/target/iscsi/iscsi_target_tpg.h b/drivers/target/iscsi/iscsi_target_tpg.h
index 2da211920c18..ceba29851167 100644
--- a/drivers/target/iscsi/iscsi_target_tpg.h
+++ b/drivers/target/iscsi/iscsi_target_tpg.h
@@ -1,6 +1,15 @@
#ifndef ISCSI_TARGET_TPG_H
#define ISCSI_TARGET_TPG_H
+#include <linux/types.h>
+
+struct iscsi_np;
+struct iscsi_session;
+struct iscsi_tiqn;
+struct iscsi_tpg_np;
+struct se_node_acl;
+struct sockaddr_storage;
+
extern struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *, u16);
extern int iscsit_load_discovery_tpg(void);
extern void iscsit_release_discovery_tpg(void);
diff --git a/drivers/target/iscsi/iscsi_target_transport.c b/drivers/target/iscsi/iscsi_target_transport.c
index 08217d62fb0d..c4eb141c6435 100644
--- a/drivers/target/iscsi/iscsi_target_transport.c
+++ b/drivers/target/iscsi/iscsi_target_transport.c
@@ -1,5 +1,6 @@
#include <linux/spinlock.h>
#include <linux/list.h>
+#include <linux/module.h>
#include <target/iscsi/iscsi_transport.h>
static LIST_HEAD(g_transport_list);
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index 1f38177207e0..b5a1b4ccba12 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -18,6 +18,7 @@
#include <linux/list.h>
#include <linux/percpu_ida.h>
+#include <net/ipv6.h> /* ipv6_addr_equal() */
#include <scsi/scsi_tcq.h>
#include <scsi/iscsi_proto.h>
#include <target/target_core_base.h>
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
index 995f1cb29d0e..8ff08856516a 100644
--- a/drivers/target/iscsi/iscsi_target_util.h
+++ b/drivers/target/iscsi/iscsi_target_util.h
@@ -1,8 +1,16 @@
#ifndef ISCSI_TARGET_UTIL_H
#define ISCSI_TARGET_UTIL_H
+#include <linux/types.h>
+#include <scsi/iscsi_proto.h> /* itt_t */
+
#define MARKER_SIZE 8
+struct iscsi_cmd;
+struct iscsi_conn;
+struct iscsi_conn_recovery;
+struct iscsi_session;
+
extern int iscsit_add_r2t_to_list(struct iscsi_cmd *, u32, u32, int, u32);
extern struct iscsi_r2t *iscsit_get_r2t_for_eos(struct iscsi_cmd *, u32, u32);
extern struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *);
diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h
index 4346462094a1..a8a230b4e6b5 100644
--- a/drivers/target/loopback/tcm_loop.h
+++ b/drivers/target/loopback/tcm_loop.h
@@ -1,3 +1,7 @@
+#include <linux/types.h>
+#include <linux/device.h>
+#include <target/target_core_base.h> /* struct se_cmd */
+
#define TCM_LOOP_VERSION "v2.1-rc2"
#define TL_WWN_ADDR_LEN 256
#define TL_TPGS_PER_HBA 32
diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c
index 58bb6ed18185..e5c3e5f827d0 100644
--- a/drivers/target/sbp/sbp_target.c
+++ b/drivers/target/sbp/sbp_target.c
@@ -28,6 +28,7 @@
#include <linux/string.h>
#include <linux/configfs.h>
#include <linux/ctype.h>
+#include <linux/delay.h>
#include <linux/firewire.h>
#include <linux/firewire-constants.h>
#include <scsi/scsi_proto.h>
@@ -928,7 +929,7 @@ static struct sbp_target_request *sbp_mgt_get_req(struct sbp_session *sess,
struct sbp_target_request *req;
int tag;
- tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC);
+ tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING);
if (tag < 0)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 4c82bbe19003..f5e330099bfc 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -26,8 +26,11 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/configfs.h>
+#include <linux/delay.h>
#include <linux/export.h>
+#include <linux/fcntl.h>
#include <linux/file.h>
+#include <linux/fs.h>
#include <scsi/scsi_proto.h>
#include <asm/unaligned.h>
diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h
index 9b250f9b33bf..c69c11baf07f 100644
--- a/drivers/target/target_core_alua.h
+++ b/drivers/target/target_core_alua.h
@@ -1,6 +1,8 @@
#ifndef TARGET_CORE_ALUA_H
#define TARGET_CORE_ALUA_H
+#include <target/target_core_base.h>
+
/*
* INQUIRY response data, TPGS Field
*
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index a35a347ec357..54b36c9835be 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -144,12 +144,12 @@ static ssize_t target_core_item_dbroot_store(struct config_item *item,
return -EINVAL;
}
if (!S_ISDIR(file_inode(fp)->i_mode)) {
- filp_close(fp, 0);
+ filp_close(fp, NULL);
mutex_unlock(&g_tf_lock);
pr_err("db_root: not a directory: %s\n", db_root_stage);
return -EINVAL;
}
- filp_close(fp, 0);
+ filp_close(fp, NULL);
strncpy(db_root, db_root_stage, read_bytes);
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index 6b423485c5d6..1ebd13ef7bd3 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -33,6 +33,7 @@
#include <linux/kthread.h>
#include <linux/in.h>
#include <linux/export.h>
+#include <linux/t10-pi.h>
#include <asm/unaligned.h>
#include <net/sock.h>
#include <net/tcp.h>
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index d545993df18b..87aa376a1a1a 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -32,6 +32,7 @@
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/falloc.h>
+#include <linux/uio.h>
#include <scsi/scsi_proto.h>
#include <asm/unaligned.h>
diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h
index 068966fce308..526595a072de 100644
--- a/drivers/target/target_core_file.h
+++ b/drivers/target/target_core_file.h
@@ -1,6 +1,8 @@
#ifndef TARGET_CORE_FILE_H
#define TARGET_CORE_FILE_H
+#include <target/target_core_base.h>
+
#define FD_VERSION "4.0"
#define FD_MAX_DEV_NAME 256
diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h
index 01c2afd81500..718d3fcd3e7c 100644
--- a/drivers/target/target_core_iblock.h
+++ b/drivers/target/target_core_iblock.h
@@ -1,6 +1,9 @@
#ifndef TARGET_CORE_IBLOCK_H
#define TARGET_CORE_IBLOCK_H
+#include <linux/atomic.h>
+#include <target/target_core_base.h>
+
#define IBLOCK_VERSION "4.0"
#define IBLOCK_MAX_CDBS 16
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index e2c970a9d61c..9ab7090f7c83 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -1,6 +1,11 @@
#ifndef TARGET_CORE_INTERNAL_H
#define TARGET_CORE_INTERNAL_H
+#include <linux/configfs.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <target/target_core_base.h>
+
#define TARGET_CORE_NAME_MAX_LEN 64
#define TARGET_FABRIC_NAME_SIZE 32
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 47463c99c318..d761025144f9 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -29,6 +29,8 @@
#include <linux/list.h>
#include <linux/vmalloc.h>
#include <linux/file.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
#include <scsi/scsi_proto.h>
#include <asm/unaligned.h>
@@ -253,8 +255,7 @@ target_scsi2_reservation_reserve(struct se_cmd *cmd)
if ((cmd->t_task_cdb[1] & 0x01) &&
(cmd->t_task_cdb[1] & 0x02)) {
- pr_err("LongIO and Obselete Bits set, returning"
- " ILLEGAL_REQUEST\n");
+ pr_err("LongIO and Obsolete Bits set, returning ILLEGAL_REQUEST\n");
return TCM_UNSUPPORTED_SCSI_OPCODE;
}
/*
diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h
index e3d26e9126a0..847bd470339c 100644
--- a/drivers/target/target_core_pr.h
+++ b/drivers/target/target_core_pr.h
@@ -1,5 +1,9 @@
#ifndef TARGET_CORE_PR_H
#define TARGET_CORE_PR_H
+
+#include <linux/types.h>
+#include <target/target_core_base.h>
+
/*
* PERSISTENT_RESERVE_OUT service action codes
*
diff --git a/drivers/target/target_core_pscsi.h b/drivers/target/target_core_pscsi.h
index 6d2007e35df6..8a02fa47c7e8 100644
--- a/drivers/target/target_core_pscsi.h
+++ b/drivers/target/target_core_pscsi.h
@@ -15,11 +15,12 @@
#define PS_TIMEOUT_DISK (15*HZ)
#define PS_TIMEOUT_OTHER (500*HZ)
-#include <linux/device.h>
-#include <linux/kref.h>
-#include <linux/kobject.h>
+#include <linux/cache.h> /* ___cacheline_aligned */
+#include <target/target_core_base.h> /* struct se_device */
+struct block_device;
struct scsi_device;
+struct Scsi_Host;
struct pscsi_plugin_task {
unsigned char pscsi_sense[TRANSPORT_SENSE_BUFFER];
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c
index 24b36fd785f1..ddc216c9f1f6 100644
--- a/drivers/target/target_core_rd.c
+++ b/drivers/target/target_core_rd.c
@@ -26,7 +26,9 @@
#include <linux/string.h>
#include <linux/parser.h>
+#include <linux/highmem.h>
#include <linux/timer.h>
+#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <scsi/scsi_proto.h>
diff --git a/drivers/target/target_core_rd.h b/drivers/target/target_core_rd.h
index cc46a6a89b38..91fc1a34791d 100644
--- a/drivers/target/target_core_rd.h
+++ b/drivers/target/target_core_rd.h
@@ -1,6 +1,10 @@
#ifndef TARGET_CORE_RD_H
#define TARGET_CORE_RD_H
+#include <linux/module.h>
+#include <linux/types.h>
+#include <target/target_core_base.h>
+
#define RD_HBA_VERSION "v4.0"
#define RD_MCP_VERSION "4.0"
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index 04f616b3ba0a..4879e70e2eef 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/ratelimit.h>
#include <linux/crc-t10dif.h>
+#include <linux/t10-pi.h>
#include <asm/unaligned.h>
#include <scsi/scsi_proto.h>
#include <scsi/scsi_tcq.h>
diff --git a/drivers/target/target_core_ua.h b/drivers/target/target_core_ua.h
index bd6e78ba153d..97402856a8f0 100644
--- a/drivers/target/target_core_ua.h
+++ b/drivers/target/target_core_ua.h
@@ -1,6 +1,8 @@
#ifndef TARGET_CORE_UA_H
#define TARGET_CORE_UA_H
+#include <target/target_core_base.h>
+
/*
* From spc4r17, Table D.1: ASC and ASCQ Assignement
*/
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index 2b3c8564ace8..8041710b6972 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -27,6 +27,7 @@
#include <linux/uio_driver.h>
#include <linux/stringify.h>
#include <linux/bitops.h>
+#include <linux/highmem.h>
#include <net/genetlink.h>
#include <scsi/scsi_common.h>
#include <scsi/scsi_proto.h>
@@ -537,7 +538,7 @@ tcmu_queue_cmd(struct se_cmd *se_cmd)
struct se_device *se_dev = se_cmd->se_dev;
struct tcmu_dev *udev = TCMU_DEV(se_dev);
struct tcmu_cmd *tcmu_cmd;
- int ret;
+ sense_reason_t ret;
tcmu_cmd = tcmu_alloc_cmd(se_cmd);
if (!tcmu_cmd)
@@ -685,8 +686,6 @@ static int tcmu_check_expired_cmd(int id, void *p, void *data)
target_complete_cmd(cmd->se_cmd, SAM_STAT_CHECK_CONDITION);
cmd->se_cmd = NULL;
- kmem_cache_free(tcmu_cmd_cache, cmd);
-
return 0;
}
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c
index 094a1440eacb..37d5caebffa6 100644
--- a/drivers/target/target_core_xcopy.c
+++ b/drivers/target/target_core_xcopy.c
@@ -25,6 +25,7 @@
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/configfs.h>
+#include <linux/ratelimit.h>
#include <scsi/scsi_proto.h>
#include <asm/unaligned.h>
diff --git a/drivers/target/target_core_xcopy.h b/drivers/target/target_core_xcopy.h
index 700a981c7b41..4d3d4dd060f2 100644
--- a/drivers/target/target_core_xcopy.h
+++ b/drivers/target/target_core_xcopy.h
@@ -1,3 +1,5 @@
+#include <target/target_core_base.h>
+
#define XCOPY_TARGET_DESC_LEN 32
#define XCOPY_SEGMENT_DESC_LEN 28
#define XCOPY_NAA_IEEE_REGEX_LEN 16
diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h
index e28209b99b59..11d27b93b413 100644
--- a/drivers/target/tcm_fc/tcm_fc.h
+++ b/drivers/target/tcm_fc/tcm_fc.h
@@ -17,6 +17,9 @@
#ifndef __TCM_FC_H__
#define __TCM_FC_H__
+#include <linux/types.h>
+#include <target/target_core_base.h>
+
#define FT_VERSION "0.4"
#define FT_NAMELEN 32 /* length of ASCII WWPNs including pad */
diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c
index 197f73386fac..d2351139342f 100644
--- a/drivers/usb/gadget/function/f_tcm.c
+++ b/drivers/usb/gadget/function/f_tcm.c
@@ -1073,7 +1073,7 @@ static struct usbg_cmd *usbg_get_cmd(struct f_uas *fu,
struct usbg_cmd *cmd;
int tag;
- tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC);
+ tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING);
if (tag < 0)
return ERR_PTR(-ENOMEM);