summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/atm/ambassador.c1
-rw-r--r--drivers/base/dma-contiguous.c24
-rw-r--r--drivers/char/hw_random/Kconfig6
-rw-r--r--drivers/char/hw_random/ixp4xx-rng.c5
-rw-r--r--drivers/char/raw.c2
-rw-r--r--drivers/clk/Kconfig16
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/clk-bcm2835.c8
-rw-r--r--drivers/clk/clk-fixed-rate.c2
-rw-r--r--drivers/clk/clk-prima2.c84
-rw-r--r--drivers/clk/clk-twl6040.c126
-rw-r--r--drivers/clk/clk-vt8500.c18
-rw-r--r--drivers/clk/clk-wm831x.c34
-rw-r--r--drivers/clk/clk.c154
-rw-r--r--drivers/clk/mxs/clk-imx23.c6
-rw-r--r--drivers/clk/mxs/clk-imx28.c10
-rw-r--r--drivers/clk/spear/clk-aux-synth.c3
-rw-r--r--drivers/clk/spear/clk-vco-pll.c2
-rw-r--r--drivers/clk/spear/clk.c3
-rw-r--r--drivers/clk/spear/spear1310_clock.c106
-rw-r--r--drivers/clk/spear/spear1340_clock.c237
-rw-r--r--drivers/clk/spear/spear3xx_clock.c154
-rw-r--r--drivers/clk/spear/spear6xx_clock.c13
-rw-r--r--drivers/clk/ux500/Makefile3
-rw-r--r--drivers/clk/ux500/abx500-clk.c73
-rw-r--r--drivers/clk/ux500/clk-prcmu.c72
-rw-r--r--drivers/clk/ux500/clk.h12
-rw-r--r--drivers/clk/ux500/u8500_clk.c28
-rw-r--r--drivers/clk/versatile/Makefile3
-rw-r--r--drivers/clk/versatile/clk-icst.c66
-rw-r--r--drivers/clk/versatile/clk-icst.h14
-rw-r--r--drivers/clk/versatile/clk-impd1.c97
-rw-r--r--drivers/clk/versatile/clk-integrator.c55
-rw-r--r--drivers/clk/versatile/clk-realview.c65
-rw-r--r--drivers/clk/versatile/clk-vexpress-osc.c146
-rw-r--r--drivers/clk/versatile/clk-vexpress.c142
-rw-r--r--drivers/cpufreq/db8500-cpufreq.c101
-rw-r--r--drivers/crypto/Kconfig2
-rw-r--r--drivers/crypto/ixp4xx_crypto.c12
-rw-r--r--drivers/edac/edac_mc.c14
-rw-r--r--drivers/edac/i7300_edac.c8
-rw-r--r--drivers/edac/i7core_edac.c6
-rw-r--r--drivers/edac/i82975x_edac.c11
-rw-r--r--drivers/gpio/gpiolib-of.c52
-rw-r--r--drivers/gpio/gpiolib.c76
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_encoder.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.c1
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c6
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c11
-rw-r--r--drivers/gpu/drm/i915/intel_display.c2
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c12
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c17
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c48
-rw-r--r--drivers/hwmon/Kconfig19
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/ads7828.c247
-rw-r--r--drivers/hwmon/coretemp.c60
-rw-r--r--drivers/hwmon/da9052-hwmon.c27
-rw-r--r--drivers/hwmon/da9055-hwmon.c336
-rw-r--r--drivers/hwmon/fam15h_power.c4
-rw-r--r--drivers/hwmon/ina2xx.c13
-rw-r--r--drivers/input/matrix-keymap.c3
-rw-r--r--drivers/md/raid1.c2
-rw-r--r--drivers/md/raid10.c2
-rw-r--r--drivers/media/dvb-frontends/stv0900_core.c6
-rw-r--r--drivers/media/i2c/adv7604.c377
-rw-r--r--drivers/media/i2c/soc_camera/mt9v022.c11
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-core.c6
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-m2m.c4
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-regs.h16
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c4
-rw-r--r--drivers/media/platform/omap3isp/ispstat.c4
-rw-r--r--drivers/media/platform/omap3isp/ispstat.h4
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c2
-rw-r--r--drivers/media/platform/s5p-fimc/Kconfig1
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-capture.c14
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-lite.c10
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-m2m.c3
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-mdevice.c41
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c7
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c2
-rw-r--r--drivers/media/platform/sh_vou.c3
-rw-r--r--drivers/media/platform/soc_camera/mx1_camera.c9
-rw-r--r--drivers/media/platform/soc_camera/mx2_camera.c13
-rw-r--r--drivers/media/platform/soc_camera/mx3_camera.c5
-rw-r--r--drivers/media/platform/soc_camera/omap1_camera.c4
-rw-r--r--drivers/media/platform/soc_camera/pxa_camera.c4
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c13
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_core.c11
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c4
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c4
-rw-r--r--drivers/mfd/arizona-core.c14
-rw-r--r--drivers/mfd/arizona-irq.c1
-rw-r--r--drivers/mfd/db8500-prcmu.c86
-rw-r--r--drivers/mfd/twl-core.c2
-rw-r--r--drivers/mfd/twl4030-irq.c3
-rw-r--r--drivers/mfd/wm5102-tables.c519
-rw-r--r--drivers/mmc/card/block.c81
-rw-r--r--drivers/mmc/card/queue.c17
-rw-r--r--drivers/mmc/core/bus.c3
-rw-r--r--drivers/mmc/core/core.c32
-rw-r--r--drivers/mmc/core/debugfs.c16
-rw-r--r--drivers/mmc/core/mmc.c19
-rw-r--r--drivers/mmc/core/mmc_ops.c11
-rw-r--r--drivers/mmc/core/sdio_bus.c17
-rw-r--r--drivers/mmc/core/sdio_io.c10
-rw-r--r--drivers/mmc/core/sdio_ops.c32
-rw-r--r--drivers/mmc/core/slot-gpio.c8
-rw-r--r--drivers/mmc/host/Kconfig33
-rw-r--r--drivers/mmc/host/Makefile2
-rw-r--r--drivers/mmc/host/at91_mci.c1219
-rw-r--r--drivers/mmc/host/at91_mci.h115
-rw-r--r--drivers/mmc/host/dw_mmc-pci.c2
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.c16
-rw-r--r--drivers/mmc/host/dw_mmc.c86
-rw-r--r--drivers/mmc/host/mxcmmc.c2
-rw-r--r--drivers/mmc/host/mxs-mmc.c31
-rw-r--r--drivers/mmc/host/omap_hsmmc.c177
-rw-r--r--drivers/mmc/host/sdhci-dove.c108
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c56
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c54
-rw-r--r--drivers/mmc/host/sdhci-pci.c1
-rw-r--r--drivers/mmc/host/sdhci-pltfm.c9
-rw-r--r--drivers/mmc/host/sdhci-pxav3.c13
-rw-r--r--drivers/mmc/host/sdhci-s3c.c65
-rw-r--r--drivers/mmc/host/sdhci-spear.c9
-rw-r--r--drivers/mmc/host/sdhci.c79
-rw-r--r--drivers/mmc/host/sdhci.h5
-rw-r--r--drivers/mmc/host/sh_mmcif.c14
-rw-r--r--drivers/mmc/host/sh_mobile_sdhi.c8
-rw-r--r--drivers/mmc/host/vub300.c1
-rw-r--r--drivers/mmc/host/wmt-sdmmc.c1029
-rw-r--r--drivers/mtd/mtdcore.c6
-rw-r--r--drivers/mtd/nand/atmel_nand.c9
-rw-r--r--drivers/mtd/ubi/wl.c26
-rw-r--r--drivers/net/bonding/bond_main.c93
-rw-r--r--drivers/net/bonding/bond_sysfs.c36
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb.c8
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_pro.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c2
-rw-r--r--drivers/net/ethernet/realtek/8139cp.c11
-rw-r--r--drivers/net/team/team.c4
-rw-r--r--drivers/net/usb/qmi_wwan.c1
-rw-r--r--drivers/net/wan/ixp4xx_hss.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/rxon.c12
-rw-r--r--drivers/pinctrl/Kconfig50
-rw-r--r--drivers/pinctrl/Makefile7
-rw-r--r--drivers/pinctrl/core.c58
-rw-r--r--drivers/pinctrl/core.h2
-rw-r--r--drivers/pinctrl/devicetree.c11
-rw-r--r--drivers/pinctrl/mvebu/Kconfig24
-rw-r--r--drivers/pinctrl/mvebu/Makefile5
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-370.c (renamed from drivers/pinctrl/pinctrl-armada-370.c)0
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-xp.c (renamed from drivers/pinctrl/pinctrl-armada-xp.c)0
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-dove.c (renamed from drivers/pinctrl/pinctrl-dove.c)0
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-kirkwood.c (renamed from drivers/pinctrl/pinctrl-kirkwood.c)0
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.c (renamed from drivers/pinctrl/pinctrl-mvebu.c)1
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.h (renamed from drivers/pinctrl/pinctrl-mvebu.h)0
-rw-r--r--drivers/pinctrl/pinconf-generic.c1
-rw-r--r--drivers/pinctrl/pinctrl-at91.c1634
-rw-r--r--drivers/pinctrl/pinctrl-bcm2835.c2
-rw-r--r--drivers/pinctrl/pinctrl-coh901.c175
-rw-r--r--drivers/pinctrl/pinctrl-exynos.c1
-rw-r--r--drivers/pinctrl/pinctrl-falcon.c2
-rw-r--r--drivers/pinctrl/pinctrl-imx.c4
-rw-r--r--drivers/pinctrl/pinctrl-lantiq.c23
-rw-r--r--drivers/pinctrl/pinctrl-mxs.c2
-rw-r--r--drivers/pinctrl/pinctrl-nomadik-db8500.c125
-rw-r--r--drivers/pinctrl/pinctrl-nomadik-db8540.c16
-rw-r--r--drivers/pinctrl/pinctrl-nomadik.c152
-rw-r--r--drivers/pinctrl/pinctrl-nomadik.h2
-rw-r--r--drivers/pinctrl/pinctrl-pxa3xx.c12
-rw-r--r--drivers/pinctrl/pinctrl-pxa3xx.h2
-rw-r--r--drivers/pinctrl/pinctrl-single.c90
-rw-r--r--drivers/pinctrl/pinctrl-sirf.c52
-rw-r--r--drivers/pinctrl/pinctrl-tegra.c24
-rw-r--r--drivers/pinctrl/pinctrl-u300.c97
-rw-r--r--drivers/pinctrl/pinctrl-xway.c2
-rw-r--r--drivers/pinctrl/pinmux.c85
-rw-r--r--drivers/pinctrl/spear/Kconfig11
-rw-r--r--drivers/pinctrl/spear/Makefile1
-rw-r--r--drivers/pinctrl/spear/pinctrl-plgpio.c758
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear.c131
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear.h60
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear1310.c264
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear1340.c27
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear300.c2
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear310.c2
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear320.c2
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear3xx.c37
-rw-r--r--drivers/remoteproc/remoteproc_virtio.c18
-rw-r--r--drivers/rtc/rtc-tps65910.c6
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c14
-rw-r--r--drivers/target/target_core_transport.c6
-rw-r--r--drivers/tty/serial/atmel_serial.c8
-rw-r--r--drivers/tty/vt/vt.c8
-rw-r--r--drivers/vhost/vhost.c2
200 files changed, 7977 insertions, 3747 deletions
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 89b30f32ba68..ff7bb8a42ed6 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -1961,6 +1961,7 @@ static int __devinit ucode_init (loader_block * lb, amb_dev * dev) {
res = loader_verify(lb, dev, rec);
if (res)
break;
+ rec = ihex_next_binrec(rec);
}
release_firmware(fw);
if (!res)
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 612afcc5a938..0ca54421ce97 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -57,8 +57,8 @@ struct cma *dma_contiguous_default_area;
* Users, who want to set the size of global CMA area for their system
* should use cma= kernel parameter.
*/
-static const unsigned long size_bytes = CMA_SIZE_MBYTES * SZ_1M;
-static long size_cmdline = -1;
+static const phys_addr_t size_bytes = CMA_SIZE_MBYTES * SZ_1M;
+static phys_addr_t size_cmdline = -1;
static int __init early_cma(char *p)
{
@@ -70,7 +70,7 @@ early_param("cma", early_cma);
#ifdef CONFIG_CMA_SIZE_PERCENTAGE
-static unsigned long __init __maybe_unused cma_early_percent_memory(void)
+static phys_addr_t __init __maybe_unused cma_early_percent_memory(void)
{
struct memblock_region *reg;
unsigned long total_pages = 0;
@@ -88,7 +88,7 @@ static unsigned long __init __maybe_unused cma_early_percent_memory(void)
#else
-static inline __maybe_unused unsigned long cma_early_percent_memory(void)
+static inline __maybe_unused phys_addr_t cma_early_percent_memory(void)
{
return 0;
}
@@ -106,7 +106,7 @@ static inline __maybe_unused unsigned long cma_early_percent_memory(void)
*/
void __init dma_contiguous_reserve(phys_addr_t limit)
{
- unsigned long selected_size = 0;
+ phys_addr_t selected_size = 0;
pr_debug("%s(limit %08lx)\n", __func__, (unsigned long)limit);
@@ -126,7 +126,7 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
if (selected_size) {
pr_debug("%s: reserving %ld MiB for global area\n", __func__,
- selected_size / SZ_1M);
+ (unsigned long)selected_size / SZ_1M);
dma_declare_contiguous(NULL, selected_size, 0, limit);
}
@@ -227,11 +227,11 @@ core_initcall(cma_init_reserved_areas);
* called by board specific code when early allocator (memblock or bootmem)
* is still activate.
*/
-int __init dma_declare_contiguous(struct device *dev, unsigned long size,
+int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
phys_addr_t base, phys_addr_t limit)
{
struct cma_reserved *r = &cma_reserved[cma_reserved_count];
- unsigned long alignment;
+ phys_addr_t alignment;
pr_debug("%s(size %lx, base %08lx, limit %08lx)\n", __func__,
(unsigned long)size, (unsigned long)base,
@@ -268,10 +268,6 @@ int __init dma_declare_contiguous(struct device *dev, unsigned long size,
if (!addr) {
base = -ENOMEM;
goto err;
- } else if (addr + size > ~(unsigned long)0) {
- memblock_free(addr, size);
- base = -EINVAL;
- goto err;
} else {
base = addr;
}
@@ -285,14 +281,14 @@ int __init dma_declare_contiguous(struct device *dev, unsigned long size,
r->size = size;
r->dev = dev;
cma_reserved_count++;
- pr_info("CMA: reserved %ld MiB at %08lx\n", size / SZ_1M,
+ pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M,
(unsigned long)base);
/* Architecture specific contiguous memory fixup. */
dma_contiguous_early_fixup(base, size);
return 0;
err:
- pr_err("CMA: failed to reserve %ld MiB\n", size / SZ_1M);
+ pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
return base;
}
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index fbd9b2b850ef..c58ea9b80b1a 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -127,12 +127,12 @@ config HW_RANDOM_VIA
If unsure, say Y.
config HW_RANDOM_IXP4XX
- tristate "Intel IXP4xx NPU HW Random Number Generator support"
+ tristate "Intel IXP4xx NPU HW Pseudo-Random Number Generator support"
depends on HW_RANDOM && ARCH_IXP4XX
default HW_RANDOM
---help---
- This driver provides kernel-side support for the Random
- Number Generator hardware found on the Intel IXP4xx NPU.
+ This driver provides kernel-side support for the Pseudo-Random
+ Number Generator hardware found on the Intel IXP45x/46x NPU.
To compile this driver as a module, choose M here: the
module will be called ixp4xx-rng.
diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c
index 263567f5f392..beec1627db3c 100644
--- a/drivers/char/hw_random/ixp4xx-rng.c
+++ b/drivers/char/hw_random/ixp4xx-rng.c
@@ -45,6 +45,9 @@ static int __init ixp4xx_rng_init(void)
void __iomem * rng_base;
int err;
+ if (!cpu_is_ixp46x()) /* includes IXP455 */
+ return -ENOSYS;
+
rng_base = ioremap(0x70002100, 4);
if (!rng_base)
return -ENOMEM;
@@ -68,5 +71,5 @@ module_init(ixp4xx_rng_init);
module_exit(ixp4xx_rng_exit);
MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
-MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver for IXP4xx");
+MODULE_DESCRIPTION("H/W Pseudo-Random Number Generator (RNG) driver for IXP45x/46x");
MODULE_LICENSE("GPL");
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 0bb207eaef2f..54a3a6d09819 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -285,7 +285,7 @@ static long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd,
static const struct file_operations raw_fops = {
.read = do_sync_read,
- .aio_read = blkdev_aio_read,
+ .aio_read = generic_file_aio_read,
.write = do_sync_write,
.aio_write = blkdev_aio_write,
.fsync = blkdev_fsync,
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index bace9e98f75d..823f62d900ba 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -42,10 +42,12 @@ config COMMON_CLK_WM831X
config COMMON_CLK_VERSATILE
bool "Clock driver for ARM Reference designs"
- depends on ARCH_INTEGRATOR || ARCH_REALVIEW
+ depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS
---help---
- Supports clocking on ARM Reference designs Integrator/AP,
- Integrator/CP, RealView PB1176, EB, PB11MP and PBX.
+ Supports clocking on ARM Reference designs:
+ - Integrator/AP and Integrator/CP
+ - RealView PB1176, EB, PB11MP and PBX
+ - Versatile Express
config COMMON_CLK_MAX77686
tristate "Clock driver for Maxim 77686 MFD"
@@ -53,4 +55,12 @@ config COMMON_CLK_MAX77686
---help---
This driver supports Maxim 77686 crystal oscillator clock.
+config CLK_TWL6040
+ tristate "External McPDM functional clock from twl6040"
+ depends on TWL6040_CORE
+ ---help---
+ Enable the external functional clock support on OMAP4+ platforms for
+ McPDM. McPDM module is using the external bit clock on the McPDM bus
+ as functional clock.
+
endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 71a25b91de00..2701235d5757 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -23,3 +23,4 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
# Chip specific
obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
+obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
diff --git a/drivers/clk/clk-bcm2835.c b/drivers/clk/clk-bcm2835.c
index 67ad16b20b81..b61ee2c5af84 100644
--- a/drivers/clk/clk-bcm2835.c
+++ b/drivers/clk/clk-bcm2835.c
@@ -33,17 +33,17 @@ void __init bcm2835_init_clocks(void)
clk = clk_register_fixed_rate(NULL, "sys_pclk", NULL, CLK_IS_ROOT,
250000000);
- if (!clk)
+ if (IS_ERR(clk))
pr_err("sys_pclk not registered\n");
clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT,
126000000);
- if (!clk)
+ if (IS_ERR(clk))
pr_err("apb_pclk not registered\n");
clk = clk_register_fixed_rate(NULL, "uart0_pclk", NULL, CLK_IS_ROOT,
3000000);
- if (!clk)
+ if (IS_ERR(clk))
pr_err("uart0_pclk not registered\n");
ret = clk_register_clkdev(clk, NULL, "20201000.uart");
if (ret)
@@ -51,7 +51,7 @@ void __init bcm2835_init_clocks(void)
clk = clk_register_fixed_rate(NULL, "uart1_pclk", NULL, CLK_IS_ROOT,
125000000);
- if (!clk)
+ if (IS_ERR(clk))
pr_err("uart1_pclk not registered\n");
ret = clk_register_clkdev(clk, NULL, "20215000.uart");
if (ret)
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c
index f5ec0eebd4d7..af78ed6b67ef 100644
--- a/drivers/clk/clk-fixed-rate.c
+++ b/drivers/clk/clk-fixed-rate.c
@@ -97,7 +97,7 @@ void __init of_fixed_clk_setup(struct device_node *node)
of_property_read_string(node, "clock-output-names", &clk_name);
clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate);
- if (clk)
+ if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk);
}
EXPORT_SYMBOL_GPL(of_fixed_clk_setup);
diff --git a/drivers/clk/clk-prima2.c b/drivers/clk/clk-prima2.c
index 517874fa6858..a203ecccdc4f 100644
--- a/drivers/clk/clk-prima2.c
+++ b/drivers/clk/clk-prima2.c
@@ -1054,118 +1054,118 @@ void __init sirfsoc_of_clk_init(void)
/* These are always available (RTC and 26MHz OSC)*/
clk = clk_register_fixed_rate(NULL, "rtc", NULL,
CLK_IS_ROOT, 32768);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register_fixed_rate(NULL, "osc", NULL,
CLK_IS_ROOT, 26000000);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_pll1.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_pll2.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_pll3.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_mem.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_sys.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_security.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b8030000.security");
clk = clk_register(NULL, &clk_dsp.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_gps.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "a8010000.gps");
clk = clk_register(NULL, &clk_mf.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_io.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "io");
clk = clk_register(NULL, &clk_cpu.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "cpu");
clk = clk_register(NULL, &clk_uart0.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0050000.uart");
clk = clk_register(NULL, &clk_uart1.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0060000.uart");
clk = clk_register(NULL, &clk_uart2.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0070000.uart");
clk = clk_register(NULL, &clk_tsc.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0110000.tsc");
clk = clk_register(NULL, &clk_i2c0.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00e0000.i2c");
clk = clk_register(NULL, &clk_i2c1.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00f0000.i2c");
clk = clk_register(NULL, &clk_spi0.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00d0000.spi");
clk = clk_register(NULL, &clk_spi1.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0170000.spi");
clk = clk_register(NULL, &clk_pwmc.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0130000.pwm");
clk = clk_register(NULL, &clk_efuse.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0140000.efusesys");
clk = clk_register(NULL, &clk_pulse.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0150000.pulsec");
clk = clk_register(NULL, &clk_dmac0.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00b0000.dma-controller");
clk = clk_register(NULL, &clk_dmac1.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0160000.dma-controller");
clk = clk_register(NULL, &clk_nand.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0030000.nand");
clk = clk_register(NULL, &clk_audio.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0040000.audio");
clk = clk_register(NULL, &clk_usp0.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0080000.usp");
clk = clk_register(NULL, &clk_usp1.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0090000.usp");
clk = clk_register(NULL, &clk_usp2.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00a0000.usp");
clk = clk_register(NULL, &clk_vip.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00c0000.vip");
clk = clk_register(NULL, &clk_gfx.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "98000000.graphics");
clk = clk_register(NULL, &clk_mm.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "a0000000.multimedia");
clk = clk_register(NULL, &clk_lcd.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "90010000.display");
clk = clk_register(NULL, &clk_vpp.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "90020000.vpp");
clk = clk_register(NULL, &clk_mmc01.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_mmc23.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_mmc45.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &usb_pll_clk_hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_usb0.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00e0000.usb");
clk = clk_register(NULL, &clk_usb1.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00f0000.usb");
}
diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c
new file mode 100644
index 000000000000..bc1e713e7b9c
--- /dev/null
+++ b/drivers/clk/clk-twl6040.c
@@ -0,0 +1,126 @@
+/*
+* TWL6040 clock module driver for OMAP4 McPDM functional clock
+*
+* Copyright (C) 2012 Texas Instruments Inc.
+* Peter Ujfalusi <peter.ujfalusi@ti.com>
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA
+*
+*/
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/twl6040.h>
+#include <linux/clk-provider.h>
+
+struct twl6040_clk {
+ struct twl6040 *twl6040;
+ struct device *dev;
+ struct clk_hw mcpdm_fclk;
+ struct clk *clk;
+ int enabled;
+};
+
+static int twl6040_bitclk_is_enabled(struct clk_hw *hw)
+{
+ struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk,
+ mcpdm_fclk);
+ return twl6040_clk->enabled;
+}
+
+static int twl6040_bitclk_prepare(struct clk_hw *hw)
+{
+ struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk,
+ mcpdm_fclk);
+ int ret;
+
+ ret = twl6040_power(twl6040_clk->twl6040, 1);
+ if (!ret)
+ twl6040_clk->enabled = 1;
+
+ return ret;
+}
+
+static void twl6040_bitclk_unprepare(struct clk_hw *hw)
+{
+ struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk,
+ mcpdm_fclk);
+ int ret;
+
+ ret = twl6040_power(twl6040_clk->twl6040, 0);
+ if (!ret)
+ twl6040_clk->enabled = 0;
+}
+
+static const struct clk_ops twl6040_mcpdm_ops = {
+ .is_enabled = twl6040_bitclk_is_enabled,
+ .prepare = twl6040_bitclk_prepare,
+ .unprepare = twl6040_bitclk_unprepare,
+};
+
+static struct clk_init_data wm831x_clkout_init = {
+ .name = "mcpdm_fclk",
+ .ops = &twl6040_mcpdm_ops,
+ .flags = CLK_IS_ROOT,
+};
+
+static int __devinit twl6040_clk_probe(struct platform_device *pdev)
+{
+ struct twl6040 *twl6040 = dev_get_drvdata(pdev->dev.parent);
+ struct twl6040_clk *clkdata;
+
+ clkdata = devm_kzalloc(&pdev->dev, sizeof(*clkdata), GFP_KERNEL);
+ if (!clkdata)
+ return -ENOMEM;
+
+ clkdata->dev = &pdev->dev;
+ clkdata->twl6040 = twl6040;
+
+ clkdata->mcpdm_fclk.init = &wm831x_clkout_init;
+ clkdata->clk = clk_register(&pdev->dev, &clkdata->mcpdm_fclk);
+ if (IS_ERR(clkdata->clk))
+ return PTR_ERR(clkdata->clk);
+
+ dev_set_drvdata(&pdev->dev, clkdata);
+
+ return 0;
+}
+
+static int __devexit twl6040_clk_remove(struct platform_device *pdev)
+{
+ struct twl6040_clk *clkdata = dev_get_drvdata(&pdev->dev);
+
+ clk_unregister(clkdata->clk);
+
+ return 0;
+}
+
+static struct platform_driver twl6040_clk_driver = {
+ .driver = {
+ .name = "twl6040-clk",
+ .owner = THIS_MODULE,
+ },
+ .probe = twl6040_clk_probe,
+ .remove = __devexit_p(twl6040_clk_remove),
+};
+
+module_platform_driver(twl6040_clk_driver);
+
+MODULE_DESCRIPTION("TWL6040 clock driver for McPDM functional clock");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_ALIAS("platform:twl6040-clk");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c
index a885600f5270..fe25570874d6 100644
--- a/drivers/clk/clk-vt8500.c
+++ b/drivers/clk/clk-vt8500.c
@@ -120,8 +120,17 @@ static unsigned long vt8500_dclk_recalc_rate(struct clk_hw *hw,
static long vt8500_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
+ struct clk_device *cdev = to_clk_device(hw);
u32 divisor = *prate / rate;
+ /*
+ * If this is a request for SDMMC we have to adjust the divisor
+ * when >31 to use the fixed predivisor
+ */
+ if ((cdev->div_mask == 0x3F) && (divisor > 31)) {
+ divisor = 64 * ((divisor / 64) + 1);
+ }
+
return *prate / divisor;
}
@@ -135,6 +144,15 @@ static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
if (divisor == cdev->div_mask + 1)
divisor = 0;
+ /* SDMMC mask may need to be corrected before testing if its valid */
+ if ((cdev->div_mask == 0x3F) && (divisor > 31)) {
+ /*
+ * Bit 5 is a fixed /64 predivisor. If the requested divisor
+ * is >31 then correct for the fixed divisor being required.
+ */
+ divisor = 0x20 + (divisor / 64);
+ }
+
if (divisor > cdev->div_mask) {
pr_err("%s: invalid divisor for clock\n", __func__);
return -EINVAL;
diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c
index e7b7765e85f3..db4fbf20ffd7 100644
--- a/drivers/clk/clk-wm831x.c
+++ b/drivers/clk/clk-wm831x.c
@@ -370,43 +370,27 @@ static __devinit int wm831x_clk_probe(struct platform_device *pdev)
clkdata->xtal_ena = ret & WM831X_XTAL_ENA;
clkdata->xtal_hw.init = &wm831x_xtal_init;
- clkdata->xtal = clk_register(&pdev->dev, &clkdata->xtal_hw);
- if (!clkdata->xtal)
- return -EINVAL;
+ clkdata->xtal = devm_clk_register(&pdev->dev, &clkdata->xtal_hw);
+ if (IS_ERR(clkdata->xtal))
+ return PTR_ERR(clkdata->xtal);
clkdata->fll_hw.init = &wm831x_fll_init;
- clkdata->fll = clk_register(&pdev->dev, &clkdata->fll_hw);
- if (!clkdata->fll) {
- ret = -EINVAL;
- goto err_xtal;
- }
+ clkdata->fll = devm_clk_register(&pdev->dev, &clkdata->fll_hw);
+ if (IS_ERR(clkdata->fll))
+ return PTR_ERR(clkdata->fll);
clkdata->clkout_hw.init = &wm831x_clkout_init;
- clkdata->clkout = clk_register(&pdev->dev, &clkdata->clkout_hw);
- if (!clkdata->clkout) {
- ret = -EINVAL;
- goto err_fll;
- }
+ clkdata->clkout = devm_clk_register(&pdev->dev, &clkdata->clkout_hw);
+ if (IS_ERR(clkdata->clkout))
+ return PTR_ERR(clkdata->clkout);
dev_set_drvdata(&pdev->dev, clkdata);
return 0;
-
-err_fll:
- clk_unregister(clkdata->fll);
-err_xtal:
- clk_unregister(clkdata->xtal);
- return ret;
}
static int __devexit wm831x_clk_remove(struct platform_device *pdev)
{
- struct wm831x_clk *clkdata = dev_get_drvdata(&pdev->dev);
-
- clk_unregister(clkdata->clkout);
- clk_unregister(clkdata->fll);
- clk_unregister(clkdata->xtal);
-
return 0;
}
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 56e4495ebeb1..251e45d6024d 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -17,6 +17,7 @@
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/of.h>
+#include <linux/device.h>
static DEFINE_SPINLOCK(enable_lock);
static DEFINE_MUTEX(prepare_lock);
@@ -218,8 +219,17 @@ static void clk_disable_unused_subtree(struct clk *clk)
if (clk->flags & CLK_IGNORE_UNUSED)
goto unlock_out;
- if (__clk_is_enabled(clk) && clk->ops->disable)
- clk->ops->disable(clk->hw);
+ /*
+ * some gate clocks have special needs during the disable-unused
+ * sequence. call .disable_unused if available, otherwise fall
+ * back to .disable
+ */
+ if (__clk_is_enabled(clk)) {
+ if (clk->ops->disable_unused)
+ clk->ops->disable_unused(clk->hw);
+ else if (clk->ops->disable)
+ clk->ops->disable(clk->hw);
+ }
unlock_out:
spin_unlock_irqrestore(&enable_lock, flags);
@@ -261,7 +271,7 @@ inline struct clk_hw *__clk_get_hw(struct clk *clk)
inline u8 __clk_get_num_parents(struct clk *clk)
{
- return !clk ? -EINVAL : clk->num_parents;
+ return !clk ? 0 : clk->num_parents;
}
inline struct clk *__clk_get_parent(struct clk *clk)
@@ -269,14 +279,14 @@ inline struct clk *__clk_get_parent(struct clk *clk)
return !clk ? NULL : clk->parent;
}
-inline int __clk_get_enable_count(struct clk *clk)
+inline unsigned int __clk_get_enable_count(struct clk *clk)
{
- return !clk ? -EINVAL : clk->enable_count;
+ return !clk ? 0 : clk->enable_count;
}
-inline int __clk_get_prepare_count(struct clk *clk)
+inline unsigned int __clk_get_prepare_count(struct clk *clk)
{
- return !clk ? -EINVAL : clk->prepare_count;
+ return !clk ? 0 : clk->prepare_count;
}
unsigned long __clk_get_rate(struct clk *clk)
@@ -302,15 +312,15 @@ out:
inline unsigned long __clk_get_flags(struct clk *clk)
{
- return !clk ? -EINVAL : clk->flags;
+ return !clk ? 0 : clk->flags;
}
-int __clk_is_enabled(struct clk *clk)
+bool __clk_is_enabled(struct clk *clk)
{
int ret;
if (!clk)
- return -EINVAL;
+ return false;
/*
* .is_enabled is only mandatory for clocks that gate
@@ -323,7 +333,7 @@ int __clk_is_enabled(struct clk *clk)
ret = clk->ops->is_enabled(clk->hw);
out:
- return ret;
+ return !!ret;
}
static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk)
@@ -568,7 +578,7 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
unsigned long parent_rate = 0;
if (!clk)
- return -EINVAL;
+ return 0;
if (!clk->ops->round_rate) {
if (clk->flags & CLK_SET_RATE_PARENT)
@@ -1297,12 +1307,20 @@ int __clk_init(struct device *dev, struct clk *clk)
* walk the list of orphan clocks and reparent any that are children of
* this clock
*/
- hlist_for_each_entry_safe(orphan, tmp, tmp2, &clk_orphan_list, child_node)
+ hlist_for_each_entry_safe(orphan, tmp, tmp2, &clk_orphan_list, child_node) {
+ if (orphan->ops->get_parent) {
+ i = orphan->ops->get_parent(orphan->hw);
+ if (!strcmp(clk->name, orphan->parent_names[i]))
+ __clk_reparent(orphan, clk);
+ continue;
+ }
+
for (i = 0; i < orphan->num_parents; i++)
if (!strcmp(clk->name, orphan->parent_names[i])) {
__clk_reparent(orphan, clk);
break;
}
+ }
/*
* optional platform-specific magic
@@ -1361,28 +1379,9 @@ struct clk *__clk_register(struct device *dev, struct clk_hw *hw)
}
EXPORT_SYMBOL_GPL(__clk_register);
-/**
- * clk_register - allocate a new clock, register it and return an opaque cookie
- * @dev: device that is registering this clock
- * @hw: link to hardware-specific clock data
- *
- * clk_register is the primary interface for populating the clock tree with new
- * clock nodes. It returns a pointer to the newly allocated struct clk which
- * cannot be dereferenced by driver code but may be used in conjuction with the
- * rest of the clock API. In the event of an error clk_register will return an
- * error code; drivers must test for an error code after calling clk_register.
- */
-struct clk *clk_register(struct device *dev, struct clk_hw *hw)
+static int _clk_register(struct device *dev, struct clk_hw *hw, struct clk *clk)
{
int i, ret;
- struct clk *clk;
-
- clk = kzalloc(sizeof(*clk), GFP_KERNEL);
- if (!clk) {
- pr_err("%s: could not allocate clk\n", __func__);
- ret = -ENOMEM;
- goto fail_out;
- }
clk->name = kstrdup(hw->init->name, GFP_KERNEL);
if (!clk->name) {
@@ -1420,7 +1419,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
ret = __clk_init(dev, clk);
if (!ret)
- return clk;
+ return 0;
fail_parent_names_copy:
while (--i >= 0)
@@ -1429,6 +1428,36 @@ fail_parent_names_copy:
fail_parent_names:
kfree(clk->name);
fail_name:
+ return ret;
+}
+
+/**
+ * clk_register - allocate a new clock, register it and return an opaque cookie
+ * @dev: device that is registering this clock
+ * @hw: link to hardware-specific clock data
+ *
+ * clk_register is the primary interface for populating the clock tree with new
+ * clock nodes. It returns a pointer to the newly allocated struct clk which
+ * cannot be dereferenced by driver code but may be used in conjuction with the
+ * rest of the clock API. In the event of an error clk_register will return an
+ * error code; drivers must test for an error code after calling clk_register.
+ */
+struct clk *clk_register(struct device *dev, struct clk_hw *hw)
+{
+ int ret;
+ struct clk *clk;
+
+ clk = kzalloc(sizeof(*clk), GFP_KERNEL);
+ if (!clk) {
+ pr_err("%s: could not allocate clk\n", __func__);
+ ret = -ENOMEM;
+ goto fail_out;
+ }
+
+ ret = _clk_register(dev, hw, clk);
+ if (!ret)
+ return clk;
+
kfree(clk);
fail_out:
return ERR_PTR(ret);
@@ -1444,6 +1473,63 @@ EXPORT_SYMBOL_GPL(clk_register);
void clk_unregister(struct clk *clk) {}
EXPORT_SYMBOL_GPL(clk_unregister);
+static void devm_clk_release(struct device *dev, void *res)
+{
+ clk_unregister(res);
+}
+
+/**
+ * devm_clk_register - resource managed clk_register()
+ * @dev: device that is registering this clock
+ * @hw: link to hardware-specific clock data
+ *
+ * Managed clk_register(). Clocks returned from this function are
+ * automatically clk_unregister()ed on driver detach. See clk_register() for
+ * more information.
+ */
+struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw)
+{
+ struct clk *clk;
+ int ret;
+
+ clk = devres_alloc(devm_clk_release, sizeof(*clk), GFP_KERNEL);
+ if (!clk)
+ return ERR_PTR(-ENOMEM);
+
+ ret = _clk_register(dev, hw, clk);
+ if (!ret) {
+ devres_add(dev, clk);
+ } else {
+ devres_free(clk);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+EXPORT_SYMBOL_GPL(devm_clk_register);
+
+static int devm_clk_match(struct device *dev, void *res, void *data)
+{
+ struct clk *c = res;
+ if (WARN_ON(!c))
+ return 0;
+ return c == data;
+}
+
+/**
+ * devm_clk_unregister - resource managed clk_unregister()
+ * @clk: clock to unregister
+ *
+ * Deallocate a clock allocated with devm_clk_register(). Normally
+ * this function will not need to be called and the resource management
+ * code will ensure that the resource is freed.
+ */
+void devm_clk_unregister(struct device *dev, struct clk *clk)
+{
+ WARN_ON(devres_release(dev, devm_clk_release, devm_clk_match, clk));
+}
+EXPORT_SYMBOL_GPL(devm_clk_unregister);
+
/*** clk rate change notifiers ***/
/**
diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c
index f00dffb9ad60..8dd476e2a9c5 100644
--- a/drivers/clk/mxs/clk-imx23.c
+++ b/drivers/clk/mxs/clk-imx23.c
@@ -85,7 +85,7 @@ enum imx23_clk {
cpu_xtal, hbus, xbus, lcdif_div, ssp_div, gpmi_div, emi_pll,
emi_xtal, etm_div, saif_div, clk32k_div, rtc, adc, spdif_div,
clk32k, dri, pwm, filt, uart, ssp, gpmi, spdif, emi, saif,
- lcdif, etm, usb, usb_pwr,
+ lcdif, etm, usb, usb_phy,
clk_max
};
@@ -143,8 +143,8 @@ int __init mx23_clocks_init(void)
clks[saif] = mxs_clk_gate("saif", "saif_div", SAIF, 31);
clks[lcdif] = mxs_clk_gate("lcdif", "lcdif_div", PIX, 31);
clks[etm] = mxs_clk_gate("etm", "etm_div", ETM, 31);
- clks[usb] = mxs_clk_gate("usb", "usb_pwr", DIGCTRL, 2);
- clks[usb_pwr] = clk_register_gate(NULL, "usb_pwr", "pll", 0, PLLCTRL0, 18, 0, &mxs_lock);
+ clks[usb] = mxs_clk_gate("usb", "usb_phy", DIGCTRL, 2);
+ clks[usb_phy] = clk_register_gate(NULL, "usb_phy", "pll", 0, PLLCTRL0, 18, 0, &mxs_lock);
for (i = 0; i < ARRAY_SIZE(clks); i++)
if (IS_ERR(clks[i])) {
diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c
index 42978f1b4bd2..db3af0874121 100644
--- a/drivers/clk/mxs/clk-imx28.c
+++ b/drivers/clk/mxs/clk-imx28.c
@@ -140,7 +140,7 @@ enum imx28_clk {
emi_xtal, lcdif_div, etm_div, ptp, saif0_div, saif1_div,
clk32k_div, rtc, lradc, spdif_div, clk32k, pwm, uart, ssp0,
ssp1, ssp2, ssp3, gpmi, spdif, emi, saif0, saif1, lcdif, etm,
- fec, can0, can1, usb0, usb1, usb0_pwr, usb1_pwr, enet_out,
+ fec, can0, can1, usb0, usb1, usb0_phy, usb1_phy, enet_out,
clk_max
};
@@ -218,10 +218,10 @@ int __init mx28_clocks_init(void)
clks[fec] = mxs_clk_gate("fec", "hbus", ENET, 30);
clks[can0] = mxs_clk_gate("can0", "ref_xtal", FLEXCAN, 30);
clks[can1] = mxs_clk_gate("can1", "ref_xtal", FLEXCAN, 28);
- clks[usb0] = mxs_clk_gate("usb0", "usb0_pwr", DIGCTRL, 2);
- clks[usb1] = mxs_clk_gate("usb1", "usb1_pwr", DIGCTRL, 16);
- clks[usb0_pwr] = clk_register_gate(NULL, "usb0_pwr", "pll0", 0, PLL0CTRL0, 18, 0, &mxs_lock);
- clks[usb1_pwr] = clk_register_gate(NULL, "usb1_pwr", "pll1", 0, PLL1CTRL0, 18, 0, &mxs_lock);
+ clks[usb0] = mxs_clk_gate("usb0", "usb0_phy", DIGCTRL, 2);
+ clks[usb1] = mxs_clk_gate("usb1", "usb1_phy", DIGCTRL, 16);
+ clks[usb0_phy] = clk_register_gate(NULL, "usb0_phy", "pll0", 0, PLL0CTRL0, 18, 0, &mxs_lock);
+ clks[usb1_phy] = clk_register_gate(NULL, "usb1_phy", "pll1", 0, PLL1CTRL0, 18, 0, &mxs_lock);
clks[enet_out] = clk_register_gate(NULL, "enet_out", "pll2", 0, ENET, 18, 0, &mxs_lock);
for (i = 0; i < ARRAY_SIZE(clks); i++)
diff --git a/drivers/clk/spear/clk-aux-synth.c b/drivers/clk/spear/clk-aux-synth.c
index 6756e7c3bc07..bdfb4421c643 100644
--- a/drivers/clk/spear/clk-aux-synth.c
+++ b/drivers/clk/spear/clk-aux-synth.c
@@ -179,7 +179,8 @@ struct clk *clk_register_aux(const char *aux_name, const char *gate_name,
if (gate_name) {
struct clk *tgate_clk;
- tgate_clk = clk_register_gate(NULL, gate_name, aux_name, 0, reg,
+ tgate_clk = clk_register_gate(NULL, gate_name, aux_name,
+ CLK_SET_RATE_PARENT, reg,
aux->masks->enable_bit, 0, lock);
if (IS_ERR_OR_NULL(tgate_clk))
goto free_aux;
diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c
index 5f1b6badeb15..1b9b65bca51e 100644
--- a/drivers/clk/spear/clk-vco-pll.c
+++ b/drivers/clk/spear/clk-vco-pll.c
@@ -147,7 +147,7 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long drate,
struct clk_pll *pll = to_clk_pll(hw);
struct pll_rate_tbl *rtbl = pll->vco->rtbl;
unsigned long flags = 0, val;
- int i;
+ int uninitialized_var(i);
clk_pll_round_rate_index(hw, drate, NULL, &i);
diff --git a/drivers/clk/spear/clk.c b/drivers/clk/spear/clk.c
index 7cd63788d546..628b6d5ed3d9 100644
--- a/drivers/clk/spear/clk.c
+++ b/drivers/clk/spear/clk.c
@@ -32,5 +32,8 @@ long clk_round_rate_index(struct clk_hw *hw, unsigned long drate,
}
}
+ if ((*index) == rtbl_cnt)
+ (*index)--;
+
return rate;
}
diff --git a/drivers/clk/spear/spear1310_clock.c b/drivers/clk/spear/spear1310_clock.c
index 0fcec2aae19c..147e25f00405 100644
--- a/drivers/clk/spear/spear1310_clock.c
+++ b/drivers/clk/spear/spear1310_clock.c
@@ -313,6 +313,20 @@ static struct aux_clk_masks i2s_sclk_masks = {
/* i2s prs1 aux rate configuration table, in ascending order of rates */
static struct aux_rate_tbl i2s_prs1_rtbl[] = {
/* For parent clk = 49.152 MHz */
+ {.xscale = 1, .yscale = 12, .eq = 0}, /* 2.048 MHz, smp freq = 8Khz */
+ {.xscale = 11, .yscale = 96, .eq = 0}, /* 2.816 MHz, smp freq = 11Khz */
+ {.xscale = 1, .yscale = 6, .eq = 0}, /* 4.096 MHz, smp freq = 16Khz */
+ {.xscale = 11, .yscale = 48, .eq = 0}, /* 5.632 MHz, smp freq = 22Khz */
+
+ /*
+ * with parent clk = 49.152, freq gen is 8.192 MHz, smp freq = 32Khz
+ * with parent clk = 12.288, freq gen is 2.048 MHz, smp freq = 8Khz
+ */
+ {.xscale = 1, .yscale = 3, .eq = 0},
+
+ /* For parent clk = 49.152 MHz */
+ {.xscale = 17, .yscale = 37, .eq = 0}, /* 11.289 MHz, smp freq = 44Khz*/
+
{.xscale = 1, .yscale = 2, .eq = 0}, /* 12.288 MHz */
};
@@ -374,9 +388,6 @@ void __init spear1310_clk_init(void)
{
struct clk *clk, *clk1;
- clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
- clk_register_clkdev(clk, "apb_pclk", NULL);
-
clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT,
32000);
clk_register_clkdev(clk, "osc_32k_clk", NULL);
@@ -401,7 +412,7 @@ void __init spear1310_clk_init(void)
clk = clk_register_gate(NULL, "rtc-spear", "osc_32k_clk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_RTC_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "fc900000.rtc");
+ clk_register_clkdev(clk, NULL, "e0580000.rtc");
/* clock derived from 24 or 25 MHz osc clk */
/* vco-pll */
@@ -483,13 +494,18 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk, "ddr_clk", NULL);
/* clock derived from pll1 clk */
- clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", 0, 1, 2);
+ clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk",
+ CLK_SET_RATE_PARENT, 1, 2);
clk_register_clkdev(clk, "cpu_clk", NULL);
clk = clk_register_fixed_factor(NULL, "wdt_clk", "cpu_clk", 0, 1,
2);
clk_register_clkdev(clk, NULL, "ec800620.wdt");
+ clk = clk_register_fixed_factor(NULL, "smp_twd_clk", "cpu_clk", 0, 1,
+ 2);
+ clk_register_clkdev(clk, NULL, "smp_twd");
+
clk = clk_register_fixed_factor(NULL, "ahb_clk", "pll1_clk", 0, 1,
6);
clk_register_clkdev(clk, "ahb_clk", NULL);
@@ -547,14 +563,14 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk1, "uart_syn_gclk", NULL);
clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents,
- ARRAY_SIZE(uart0_parents), 0, SPEAR1310_PERIP_CLK_CFG,
- SPEAR1310_UART_CLK_SHIFT, SPEAR1310_UART_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(uart0_parents), CLK_SET_RATE_PARENT,
+ SPEAR1310_PERIP_CLK_CFG, SPEAR1310_UART_CLK_SHIFT,
+ SPEAR1310_UART_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "uart0_mclk", NULL);
- clk = clk_register_gate(NULL, "uart0_clk", "uart0_mclk", 0,
- SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_UART_CLK_ENB, 0,
- &_lock);
+ clk = clk_register_gate(NULL, "uart0_clk", "uart0_mclk",
+ CLK_SET_RATE_PARENT, SPEAR1310_PERIP1_CLK_ENB,
+ SPEAR1310_UART_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "e0000000.serial");
clk = clk_register_aux("sdhci_syn_clk", "sdhci_syn_gclk",
@@ -563,9 +579,9 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk, "sdhci_syn_clk", NULL);
clk_register_clkdev(clk1, "sdhci_syn_gclk", NULL);
- clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_syn_gclk", 0,
- SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_SDHCI_CLK_ENB, 0,
- &_lock);
+ clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_syn_gclk",
+ CLK_SET_RATE_PARENT, SPEAR1310_PERIP1_CLK_ENB,
+ SPEAR1310_SDHCI_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "b3000000.sdhci");
clk = clk_register_aux("cfxd_syn_clk", "cfxd_syn_gclk", "vco1div2_clk",
@@ -574,9 +590,9 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk, "cfxd_syn_clk", NULL);
clk_register_clkdev(clk1, "cfxd_syn_gclk", NULL);
- clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_syn_gclk", 0,
- SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_CFXD_CLK_ENB, 0,
- &_lock);
+ clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_syn_gclk",
+ CLK_SET_RATE_PARENT, SPEAR1310_PERIP1_CLK_ENB,
+ SPEAR1310_CFXD_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "b2800000.cf");
clk_register_clkdev(clk, NULL, "arasan_xd");
@@ -587,9 +603,9 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk1, "c3_syn_gclk", NULL);
clk = clk_register_mux(NULL, "c3_mclk", c3_parents,
- ARRAY_SIZE(c3_parents), 0, SPEAR1310_PERIP_CLK_CFG,
- SPEAR1310_C3_CLK_SHIFT, SPEAR1310_C3_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(c3_parents), CLK_SET_RATE_PARENT,
+ SPEAR1310_PERIP_CLK_CFG, SPEAR1310_C3_CLK_SHIFT,
+ SPEAR1310_C3_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "c3_mclk", NULL);
clk = clk_register_gate(NULL, "c3_clk", "c3_mclk", 0,
@@ -615,7 +631,7 @@ void __init spear1310_clk_init(void)
ARRAY_SIZE(gmac_phy_parents), 0,
SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GMAC_PHY_CLK_SHIFT,
SPEAR1310_GMAC_PHY_CLK_MASK, 0, &_lock);
- clk_register_clkdev(clk, NULL, "stmmacphy.0");
+ clk_register_clkdev(clk, "stmmacphy.0", NULL);
/* clcd */
clk = clk_register_mux(NULL, "clcd_syn_mclk", clcd_synth_parents,
@@ -630,22 +646,22 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk, "clcd_syn_clk", NULL);
clk = clk_register_mux(NULL, "clcd_pixel_mclk", clcd_pixel_parents,
- ARRAY_SIZE(clcd_pixel_parents), 0,
+ ARRAY_SIZE(clcd_pixel_parents), CLK_SET_RATE_PARENT,
SPEAR1310_PERIP_CLK_CFG, SPEAR1310_CLCD_CLK_SHIFT,
SPEAR1310_CLCD_CLK_MASK, 0, &_lock);
- clk_register_clkdev(clk, "clcd_pixel_clk", NULL);
+ clk_register_clkdev(clk, "clcd_pixel_mclk", NULL);
clk = clk_register_gate(NULL, "clcd_clk", "clcd_pixel_mclk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_CLCD_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, "clcd_clk", NULL);
+ clk_register_clkdev(clk, NULL, "e1000000.clcd");
/* i2s */
clk = clk_register_mux(NULL, "i2s_src_mclk", i2s_src_parents,
ARRAY_SIZE(i2s_src_parents), 0, SPEAR1310_I2S_CLK_CFG,
SPEAR1310_I2S_SRC_CLK_SHIFT, SPEAR1310_I2S_SRC_CLK_MASK,
0, &_lock);
- clk_register_clkdev(clk, "i2s_src_clk", NULL);
+ clk_register_clkdev(clk, "i2s_src_mclk", NULL);
clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mclk", 0,
SPEAR1310_I2S_CLK_CFG, &i2s_prs1_masks, i2s_prs1_rtbl,
@@ -653,10 +669,10 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk, "i2s_prs1_clk", NULL);
clk = clk_register_mux(NULL, "i2s_ref_mclk", i2s_ref_parents,
- ARRAY_SIZE(i2s_ref_parents), 0, SPEAR1310_I2S_CLK_CFG,
- SPEAR1310_I2S_REF_SHIFT, SPEAR1310_I2S_REF_SEL_MASK, 0,
- &_lock);
- clk_register_clkdev(clk, "i2s_ref_clk", NULL);
+ ARRAY_SIZE(i2s_ref_parents), CLK_SET_RATE_PARENT,
+ SPEAR1310_I2S_CLK_CFG, SPEAR1310_I2S_REF_SHIFT,
+ SPEAR1310_I2S_REF_SEL_MASK, 0, &_lock);
+ clk_register_clkdev(clk, "i2s_ref_mclk", NULL);
clk = clk_register_gate(NULL, "i2s_ref_pad_clk", "i2s_ref_mclk", 0,
SPEAR1310_PERIP2_CLK_ENB, SPEAR1310_I2S_REF_PAD_CLK_ENB,
@@ -664,7 +680,7 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk, "i2s_ref_pad_clk", NULL);
clk = clk_register_aux("i2s_sclk_clk", "i2s_sclk_gclk",
- "i2s_ref_pad_clk", 0, SPEAR1310_I2S_CLK_CFG,
+ "i2s_ref_mclk", 0, SPEAR1310_I2S_CLK_CFG,
&i2s_sclk_masks, i2s_sclk_rtbl,
ARRAY_SIZE(i2s_sclk_rtbl), &_lock, &clk1);
clk_register_clkdev(clk, "i2s_sclk_clk", NULL);
@@ -705,35 +721,37 @@ void __init spear1310_clk_init(void)
clk = clk_register_gate(NULL, "usbh0_clk", "ahb_clk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_UHC0_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, "usbh.0_clk", NULL);
+ clk_register_clkdev(clk, NULL, "e4000000.ohci");
+ clk_register_clkdev(clk, NULL, "e4800000.ehci");
clk = clk_register_gate(NULL, "usbh1_clk", "ahb_clk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_UHC1_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, "usbh.1_clk", NULL);
+ clk_register_clkdev(clk, NULL, "e5000000.ohci");
+ clk_register_clkdev(clk, NULL, "e5800000.ehci");
clk = clk_register_gate(NULL, "uoc_clk", "ahb_clk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_UOC_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "uoc");
+ clk_register_clkdev(clk, NULL, "e3800000.otg");
clk = clk_register_gate(NULL, "pcie_sata_0_clk", "ahb_clk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_PCIE_SATA_0_CLK_ENB,
0, &_lock);
clk_register_clkdev(clk, NULL, "dw_pcie.0");
- clk_register_clkdev(clk, NULL, "ahci.0");
+ clk_register_clkdev(clk, NULL, "b1000000.ahci");
clk = clk_register_gate(NULL, "pcie_sata_1_clk", "ahb_clk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_PCIE_SATA_1_CLK_ENB,
0, &_lock);
clk_register_clkdev(clk, NULL, "dw_pcie.1");
- clk_register_clkdev(clk, NULL, "ahci.1");
+ clk_register_clkdev(clk, NULL, "b1800000.ahci");
clk = clk_register_gate(NULL, "pcie_sata_2_clk", "ahb_clk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_PCIE_SATA_2_CLK_ENB,
0, &_lock);
clk_register_clkdev(clk, NULL, "dw_pcie.2");
- clk_register_clkdev(clk, NULL, "ahci.2");
+ clk_register_clkdev(clk, NULL, "b4000000.ahci");
clk = clk_register_gate(NULL, "sysram0_clk", "ahb_clk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_SYSRAM0_CLK_ENB, 0,
@@ -751,10 +769,10 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk, "adc_syn_clk", NULL);
clk_register_clkdev(clk1, "adc_syn_gclk", NULL);
- clk = clk_register_gate(NULL, "adc_clk", "adc_syn_gclk", 0,
- SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_ADC_CLK_ENB, 0,
- &_lock);
- clk_register_clkdev(clk, NULL, "adc_clk");
+ clk = clk_register_gate(NULL, "adc_clk", "adc_syn_gclk",
+ CLK_SET_RATE_PARENT, SPEAR1310_PERIP1_CLK_ENB,
+ SPEAR1310_ADC_CLK_ENB, 0, &_lock);
+ clk_register_clkdev(clk, NULL, "e0080000.adc");
/* clock derived from apb clk */
clk = clk_register_gate(NULL, "ssp0_clk", "apb_clk", 0,
@@ -916,15 +934,15 @@ void __init spear1310_clk_init(void)
SPEAR1310_RAS_CTRL_REG1,
SPEAR1310_SMII_RGMII_PHY_CLK_SHIFT,
SPEAR1310_PHY_CLK_MASK, 0, &_lock);
- clk_register_clkdev(clk, NULL, "stmmacphy.1");
- clk_register_clkdev(clk, NULL, "stmmacphy.2");
- clk_register_clkdev(clk, NULL, "stmmacphy.4");
+ clk_register_clkdev(clk, "stmmacphy.1", NULL);
+ clk_register_clkdev(clk, "stmmacphy.2", NULL);
+ clk_register_clkdev(clk, "stmmacphy.4", NULL);
clk = clk_register_mux(NULL, "rmii_phy_mclk", rmii_phy_parents,
ARRAY_SIZE(rmii_phy_parents), 0,
SPEAR1310_RAS_CTRL_REG1, SPEAR1310_RMII_PHY_CLK_SHIFT,
SPEAR1310_PHY_CLK_MASK, 0, &_lock);
- clk_register_clkdev(clk, NULL, "stmmacphy.3");
+ clk_register_clkdev(clk, "stmmacphy.3", NULL);
clk = clk_register_mux(NULL, "uart1_mclk", uart_parents,
ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0,
diff --git a/drivers/clk/spear/spear1340_clock.c b/drivers/clk/spear/spear1340_clock.c
index 2352cee7f645..82abea366b78 100644
--- a/drivers/clk/spear/spear1340_clock.c
+++ b/drivers/clk/spear/spear1340_clock.c
@@ -190,6 +190,7 @@ static struct pll_rate_tbl pll4_rtbl[] = {
* different values of vco1div2
*/
static struct frac_rate_tbl amba_synth_rtbl[] = {
+ {.div = 0x073A8}, /* for vco1div2 = 600 MHz */
{.div = 0x06062}, /* for vco1div2 = 500 MHz */
{.div = 0x04D1B}, /* for vco1div2 = 400 MHz */
{.div = 0x04000}, /* for vco1div2 = 332 MHz */
@@ -220,6 +221,12 @@ static struct frac_rate_tbl amba_synth_rtbl[] = {
* 500 400 200 0x02800
* 500 500 250 0x02000
* --------------------------------------------------------------------
+ * 600 200 100 0x06000
+ * 600 250 125 0x04CCE
+ * 600 332 166 0x039D5
+ * 600 400 200 0x03000
+ * 600 500 250 0x02666
+ * --------------------------------------------------------------------
* 664 200 100 0x06a38
* 664 250 125 0x054FD
* 664 332 166 0x04000
@@ -238,28 +245,50 @@ static struct frac_rate_tbl sys_synth_rtbl[] = {
{.div = 0x08000},
{.div = 0x06a38},
{.div = 0x06666},
+ {.div = 0x06000},
{.div = 0x054FD},
{.div = 0x05000},
{.div = 0x04D18},
+ {.div = 0x04CCE},
{.div = 0x04000},
+ {.div = 0x039D5},
{.div = 0x0351E},
{.div = 0x03333},
{.div = 0x03031},
+ {.div = 0x03000},
{.div = 0x02A7E},
{.div = 0x02800},
{.div = 0x0268D},
+ {.div = 0x02666},
{.div = 0x02000},
};
/* aux rate configuration table, in ascending order of rates */
static struct aux_rate_tbl aux_rtbl[] = {
- /* For VCO1div2 = 500 MHz */
- {.xscale = 10, .yscale = 204, .eq = 0}, /* 12.29 MHz */
- {.xscale = 4, .yscale = 21, .eq = 0}, /* 48 MHz */
- {.xscale = 2, .yscale = 6, .eq = 0}, /* 83 MHz */
- {.xscale = 2, .yscale = 4, .eq = 0}, /* 125 MHz */
- {.xscale = 1, .yscale = 3, .eq = 1}, /* 166 MHz */
- {.xscale = 1, .yscale = 2, .eq = 1}, /* 250 MHz */
+ /* 12.29MHz for vic1div2=600MHz and 10.24MHz for VCO1div2=500MHz */
+ {.xscale = 5, .yscale = 122, .eq = 0},
+ /* 14.70MHz for vic1div2=600MHz and 12.29MHz for VCO1div2=500MHz */
+ {.xscale = 10, .yscale = 204, .eq = 0},
+ /* 48MHz for vic1div2=600MHz and 40 MHz for VCO1div2=500MHz */
+ {.xscale = 4, .yscale = 25, .eq = 0},
+ /* 57.14MHz for vic1div2=600MHz and 48 MHz for VCO1div2=500MHz */
+ {.xscale = 4, .yscale = 21, .eq = 0},
+ /* 83.33MHz for vic1div2=600MHz and 69.44MHz for VCO1div2=500MHz */
+ {.xscale = 5, .yscale = 18, .eq = 0},
+ /* 100MHz for vic1div2=600MHz and 83.33 MHz for VCO1div2=500MHz */
+ {.xscale = 2, .yscale = 6, .eq = 0},
+ /* 125MHz for vic1div2=600MHz and 104.1MHz for VCO1div2=500MHz */
+ {.xscale = 5, .yscale = 12, .eq = 0},
+ /* 150MHz for vic1div2=600MHz and 125MHz for VCO1div2=500MHz */
+ {.xscale = 2, .yscale = 4, .eq = 0},
+ /* 166MHz for vic1div2=600MHz and 138.88MHz for VCO1div2=500MHz */
+ {.xscale = 5, .yscale = 18, .eq = 1},
+ /* 200MHz for vic1div2=600MHz and 166MHz for VCO1div2=500MHz */
+ {.xscale = 1, .yscale = 3, .eq = 1},
+ /* 250MHz for vic1div2=600MHz and 208.33MHz for VCO1div2=500MHz */
+ {.xscale = 5, .yscale = 12, .eq = 1},
+ /* 300MHz for vic1div2=600MHz and 250MHz for VCO1div2=500MHz */
+ {.xscale = 1, .yscale = 2, .eq = 1},
};
/* gmac rate configuration table, in ascending order of rates */
@@ -273,16 +302,23 @@ static struct aux_rate_tbl gmac_rtbl[] = {
/* clcd rate configuration table, in ascending order of rates */
static struct frac_rate_tbl clcd_rtbl[] = {
+ {.div = 0x18000}, /* 25 Mhz , for vc01div4 = 300 MHz*/
+ {.div = 0x1638E}, /* 27 Mhz , for vc01div4 = 300 MHz*/
{.div = 0x14000}, /* 25 Mhz , for vc01div4 = 250 MHz*/
{.div = 0x1284B}, /* 27 Mhz , for vc01div4 = 250 MHz*/
{.div = 0x0D8D3}, /* 58 Mhz , for vco1div4 = 393 MHz */
{.div = 0x0B72C}, /* 58 Mhz , for vco1div4 = 332 MHz */
+ {.div = 0x0A584}, /* 58 Mhz , for vco1div4 = 300 MHz */
+ {.div = 0x093B1}, /* 65 Mhz , for vc01div4 = 300 MHz*/
{.div = 0x089EE}, /* 58 Mhz , for vc01div4 = 250 MHz*/
+ {.div = 0x081BA}, /* 74 Mhz , for vc01div4 = 300 MHz*/
{.div = 0x07BA0}, /* 65 Mhz , for vc01div4 = 250 MHz*/
{.div = 0x06f1C}, /* 72 Mhz , for vc01div4 = 250 MHz*/
{.div = 0x06E58}, /* 58 Mhz , for vco1div4 = 200 MHz */
{.div = 0x06c1B}, /* 74 Mhz , for vc01div4 = 250 MHz*/
+ {.div = 0x058E3}, /* 108 Mhz , for vc01div4 = 300 MHz*/
{.div = 0x04A12}, /* 108 Mhz , for vc01div4 = 250 MHz*/
+ {.div = 0x040A5}, /* 148.5 Mhz , for vc01div4 = 300 MHz*/
{.div = 0x0378E}, /* 144 Mhz , for vc01div4 = 250 MHz*/
{.div = 0x0360D}, /* 148 Mhz , for vc01div4 = 250 MHz*/
{.div = 0x035E0}, /* 148.5 MHz, for vc01div4 = 250 MHz*/
@@ -351,26 +387,37 @@ static struct aux_rate_tbl adc_rtbl[] = {
/* General synth rate configuration table, in ascending order of rates */
static struct frac_rate_tbl gen_rtbl[] = {
- /* For vco1div4 = 250 MHz */
- {.div = 0x1624E}, /* 22.5792 MHz */
- {.div = 0x14585}, /* 24.576 MHz */
- {.div = 0x14000}, /* 25 MHz */
- {.div = 0x0B127}, /* 45.1584 MHz */
- {.div = 0x0A000}, /* 50 MHz */
- {.div = 0x061A8}, /* 81.92 MHz */
- {.div = 0x05000}, /* 100 MHz */
- {.div = 0x02800}, /* 200 MHz */
- {.div = 0x02620}, /* 210 MHz */
- {.div = 0x02460}, /* 220 MHz */
- {.div = 0x022C0}, /* 230 MHz */
- {.div = 0x02160}, /* 240 MHz */
- {.div = 0x02000}, /* 250 MHz */
+ {.div = 0x1A92B}, /* 22.5792 MHz for vco1div4=300 MHz*/
+ {.div = 0x186A0}, /* 24.576 MHz for vco1div4=300 MHz*/
+ {.div = 0x18000}, /* 25 MHz for vco1div4=300 MHz*/
+ {.div = 0x1624E}, /* 22.5792 MHz for vco1div4=250 MHz*/
+ {.div = 0x14585}, /* 24.576 MHz for vco1div4=250 MHz*/
+ {.div = 0x14000}, /* 25 MHz for vco1div4=250 MHz*/
+ {.div = 0x0D495}, /* 45.1584 MHz for vco1div4=300 MHz*/
+ {.div = 0x0C000}, /* 50 MHz for vco1div4=300 MHz*/
+ {.div = 0x0B127}, /* 45.1584 MHz for vco1div4=250 MHz*/
+ {.div = 0x0A000}, /* 50 MHz for vco1div4=250 MHz*/
+ {.div = 0x07530}, /* 81.92 MHz for vco1div4=300 MHz*/
+ {.div = 0x061A8}, /* 81.92 MHz for vco1div4=250 MHz*/
+ {.div = 0x06000}, /* 100 MHz for vco1div4=300 MHz*/
+ {.div = 0x05000}, /* 100 MHz for vco1div4=250 MHz*/
+ {.div = 0x03000}, /* 200 MHz for vco1div4=300 MHz*/
+ {.div = 0x02DB6}, /* 210 MHz for vco1div4=300 MHz*/
+ {.div = 0x02BA2}, /* 220 MHz for vco1div4=300 MHz*/
+ {.div = 0x029BD}, /* 230 MHz for vco1div4=300 MHz*/
+ {.div = 0x02800}, /* 200 MHz for vco1div4=250 MHz*/
+ {.div = 0x02666}, /* 250 MHz for vco1div4=300 MHz*/
+ {.div = 0x02620}, /* 210 MHz for vco1div4=250 MHz*/
+ {.div = 0x02460}, /* 220 MHz for vco1div4=250 MHz*/
+ {.div = 0x022C0}, /* 230 MHz for vco1div4=250 MHz*/
+ {.div = 0x02160}, /* 240 MHz for vco1div4=250 MHz*/
+ {.div = 0x02000}, /* 250 MHz for vco1div4=250 MHz*/
};
/* clock parents */
static const char *vco_parents[] = { "osc_24m_clk", "osc_25m_clk", };
static const char *sys_parents[] = { "pll1_clk", "pll1_clk", "pll1_clk",
- "pll1_clk", "sys_synth_clk", "sys_synth_clk", "pll2_clk", "pll3_clk", };
+ "pll1_clk", "sys_syn_clk", "sys_syn_clk", "pll2_clk", "pll3_clk", };
static const char *ahb_parents[] = { "cpu_div3_clk", "amba_syn_clk", };
static const char *gpt_parents[] = { "osc_24m_clk", "apb_clk", };
static const char *uart0_parents[] = { "pll5_clk", "osc_24m_clk",
@@ -391,16 +438,13 @@ static const char *spdif_in_parents[] = { "pll2_clk", "gen_syn3_clk", };
static const char *gen_synth0_1_parents[] = { "vco1div4_clk", "vco3div2_clk",
"pll3_clk", };
-static const char *gen_synth2_3_parents[] = { "vco1div4_clk", "vco3div2_clk",
+static const char *gen_synth2_3_parents[] = { "vco1div4_clk", "vco2div2_clk",
"pll2_clk", };
void __init spear1340_clk_init(void)
{
struct clk *clk, *clk1;
- clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
- clk_register_clkdev(clk, "apb_pclk", NULL);
-
clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT,
32000);
clk_register_clkdev(clk, "osc_32k_clk", NULL);
@@ -425,7 +469,7 @@ void __init spear1340_clk_init(void)
clk = clk_register_gate(NULL, "rtc-spear", "osc_32k_clk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_RTC_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "fc900000.rtc");
+ clk_register_clkdev(clk, NULL, "e0580000.rtc");
/* clock derived from 24 or 25 MHz osc clk */
/* vco-pll */
@@ -499,7 +543,7 @@ void __init spear1340_clk_init(void)
clk = clk_register_gate(NULL, "thermal_gclk", "thermal_clk", 0,
SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_THSENS_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "spear_thermal");
+ clk_register_clkdev(clk, NULL, "e07008c4.thermal");
/* clock derived from pll4 clk */
clk = clk_register_fixed_factor(NULL, "ddr_clk", "pll4_clk", 0, 1,
@@ -521,7 +565,7 @@ void __init spear1340_clk_init(void)
ARRAY_SIZE(sys_parents), 0, SPEAR1340_SYS_CLK_CTRL,
SPEAR1340_SCLK_SRC_SEL_SHIFT,
SPEAR1340_SCLK_SRC_SEL_MASK, 0, &_lock);
- clk_register_clkdev(clk, "sys_clk", NULL);
+ clk_register_clkdev(clk, "sys_mclk", NULL);
clk = clk_register_fixed_factor(NULL, "cpu_clk", "sys_mclk", 0, 1,
2);
@@ -535,6 +579,10 @@ void __init spear1340_clk_init(void)
2);
clk_register_clkdev(clk, NULL, "ec800620.wdt");
+ clk = clk_register_fixed_factor(NULL, "smp_twd_clk", "cpu_clk", 0, 1,
+ 2);
+ clk_register_clkdev(clk, NULL, "smp_twd");
+
clk = clk_register_mux(NULL, "ahb_clk", ahb_parents,
ARRAY_SIZE(ahb_parents), 0, SPEAR1340_SYS_CLK_CTRL,
SPEAR1340_HCLK_SRC_SEL_SHIFT,
@@ -594,14 +642,14 @@ void __init spear1340_clk_init(void)
clk_register_clkdev(clk1, "uart0_syn_gclk", NULL);
clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents,
- ARRAY_SIZE(uart0_parents), 0, SPEAR1340_PERIP_CLK_CFG,
- SPEAR1340_UART0_CLK_SHIFT, SPEAR1340_UART_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(uart0_parents), CLK_SET_RATE_PARENT,
+ SPEAR1340_PERIP_CLK_CFG, SPEAR1340_UART0_CLK_SHIFT,
+ SPEAR1340_UART_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "uart0_mclk", NULL);
- clk = clk_register_gate(NULL, "uart0_clk", "uart0_mclk", 0,
- SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_UART0_CLK_ENB, 0,
- &_lock);
+ clk = clk_register_gate(NULL, "uart0_clk", "uart0_mclk",
+ CLK_SET_RATE_PARENT, SPEAR1340_PERIP1_CLK_ENB,
+ SPEAR1340_UART0_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "e0000000.serial");
clk = clk_register_aux("uart1_syn_clk", "uart1_syn_gclk",
@@ -627,9 +675,9 @@ void __init spear1340_clk_init(void)
clk_register_clkdev(clk, "sdhci_syn_clk", NULL);
clk_register_clkdev(clk1, "sdhci_syn_gclk", NULL);
- clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_syn_gclk", 0,
- SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_SDHCI_CLK_ENB, 0,
- &_lock);
+ clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_syn_gclk",
+ CLK_SET_RATE_PARENT, SPEAR1340_PERIP1_CLK_ENB,
+ SPEAR1340_SDHCI_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "b3000000.sdhci");
clk = clk_register_aux("cfxd_syn_clk", "cfxd_syn_gclk", "vco1div2_clk",
@@ -638,9 +686,9 @@ void __init spear1340_clk_init(void)
clk_register_clkdev(clk, "cfxd_syn_clk", NULL);
clk_register_clkdev(clk1, "cfxd_syn_gclk", NULL);
- clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_syn_gclk", 0,
- SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_CFXD_CLK_ENB, 0,
- &_lock);
+ clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_syn_gclk",
+ CLK_SET_RATE_PARENT, SPEAR1340_PERIP1_CLK_ENB,
+ SPEAR1340_CFXD_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "b2800000.cf");
clk_register_clkdev(clk, NULL, "arasan_xd");
@@ -651,15 +699,15 @@ void __init spear1340_clk_init(void)
clk_register_clkdev(clk1, "c3_syn_gclk", NULL);
clk = clk_register_mux(NULL, "c3_mclk", c3_parents,
- ARRAY_SIZE(c3_parents), 0, SPEAR1340_PERIP_CLK_CFG,
- SPEAR1340_C3_CLK_SHIFT, SPEAR1340_C3_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(c3_parents), CLK_SET_RATE_PARENT,
+ SPEAR1340_PERIP_CLK_CFG, SPEAR1340_C3_CLK_SHIFT,
+ SPEAR1340_C3_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "c3_mclk", NULL);
- clk = clk_register_gate(NULL, "c3_clk", "c3_mclk", 0,
+ clk = clk_register_gate(NULL, "c3_clk", "c3_mclk", CLK_SET_RATE_PARENT,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_C3_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "c3");
+ clk_register_clkdev(clk, NULL, "e1800000.c3");
/* gmac */
clk = clk_register_mux(NULL, "phy_input_mclk", gmac_phy_input_parents,
@@ -679,7 +727,7 @@ void __init spear1340_clk_init(void)
ARRAY_SIZE(gmac_phy_parents), 0,
SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GMAC_PHY_CLK_SHIFT,
SPEAR1340_GMAC_PHY_CLK_MASK, 0, &_lock);
- clk_register_clkdev(clk, NULL, "stmmacphy.0");
+ clk_register_clkdev(clk, "stmmacphy.0", NULL);
/* clcd */
clk = clk_register_mux(NULL, "clcd_syn_mclk", clcd_synth_parents,
@@ -694,33 +742,34 @@ void __init spear1340_clk_init(void)
clk_register_clkdev(clk, "clcd_syn_clk", NULL);
clk = clk_register_mux(NULL, "clcd_pixel_mclk", clcd_pixel_parents,
- ARRAY_SIZE(clcd_pixel_parents), 0,
+ ARRAY_SIZE(clcd_pixel_parents), CLK_SET_RATE_PARENT,
SPEAR1340_PERIP_CLK_CFG, SPEAR1340_CLCD_CLK_SHIFT,
SPEAR1340_CLCD_CLK_MASK, 0, &_lock);
- clk_register_clkdev(clk, "clcd_pixel_clk", NULL);
+ clk_register_clkdev(clk, "clcd_pixel_mclk", NULL);
clk = clk_register_gate(NULL, "clcd_clk", "clcd_pixel_mclk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_CLCD_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, "clcd_clk", NULL);
+ clk_register_clkdev(clk, NULL, "e1000000.clcd");
/* i2s */
clk = clk_register_mux(NULL, "i2s_src_mclk", i2s_src_parents,
ARRAY_SIZE(i2s_src_parents), 0, SPEAR1340_I2S_CLK_CFG,
SPEAR1340_I2S_SRC_CLK_SHIFT, SPEAR1340_I2S_SRC_CLK_MASK,
0, &_lock);
- clk_register_clkdev(clk, "i2s_src_clk", NULL);
+ clk_register_clkdev(clk, "i2s_src_mclk", NULL);
- clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mclk", 0,
- SPEAR1340_I2S_CLK_CFG, &i2s_prs1_masks, i2s_prs1_rtbl,
+ clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mclk",
+ CLK_SET_RATE_PARENT, SPEAR1340_I2S_CLK_CFG,
+ &i2s_prs1_masks, i2s_prs1_rtbl,
ARRAY_SIZE(i2s_prs1_rtbl), &_lock, NULL);
clk_register_clkdev(clk, "i2s_prs1_clk", NULL);
clk = clk_register_mux(NULL, "i2s_ref_mclk", i2s_ref_parents,
- ARRAY_SIZE(i2s_ref_parents), 0, SPEAR1340_I2S_CLK_CFG,
- SPEAR1340_I2S_REF_SHIFT, SPEAR1340_I2S_REF_SEL_MASK, 0,
- &_lock);
- clk_register_clkdev(clk, "i2s_ref_clk", NULL);
+ ARRAY_SIZE(i2s_ref_parents), CLK_SET_RATE_PARENT,
+ SPEAR1340_I2S_CLK_CFG, SPEAR1340_I2S_REF_SHIFT,
+ SPEAR1340_I2S_REF_SEL_MASK, 0, &_lock);
+ clk_register_clkdev(clk, "i2s_ref_mclk", NULL);
clk = clk_register_gate(NULL, "i2s_ref_pad_clk", "i2s_ref_mclk", 0,
SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_I2S_REF_PAD_CLK_ENB,
@@ -769,23 +818,25 @@ void __init spear1340_clk_init(void)
clk = clk_register_gate(NULL, "usbh0_clk", "ahb_clk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_UHC0_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, "usbh.0_clk", NULL);
+ clk_register_clkdev(clk, NULL, "e4000000.ohci");
+ clk_register_clkdev(clk, NULL, "e4800000.ehci");
clk = clk_register_gate(NULL, "usbh1_clk", "ahb_clk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_UHC1_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, "usbh.1_clk", NULL);
+ clk_register_clkdev(clk, NULL, "e5000000.ohci");
+ clk_register_clkdev(clk, NULL, "e5800000.ehci");
clk = clk_register_gate(NULL, "uoc_clk", "ahb_clk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_UOC_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "uoc");
+ clk_register_clkdev(clk, NULL, "e3800000.otg");
clk = clk_register_gate(NULL, "pcie_sata_clk", "ahb_clk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_PCIE_SATA_CLK_ENB,
0, &_lock);
clk_register_clkdev(clk, NULL, "dw_pcie");
- clk_register_clkdev(clk, NULL, "ahci");
+ clk_register_clkdev(clk, NULL, "b1000000.ahci");
clk = clk_register_gate(NULL, "sysram0_clk", "ahb_clk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_SYSRAM0_CLK_ENB, 0,
@@ -803,10 +854,10 @@ void __init spear1340_clk_init(void)
clk_register_clkdev(clk, "adc_syn_clk", NULL);
clk_register_clkdev(clk1, "adc_syn_gclk", NULL);
- clk = clk_register_gate(NULL, "adc_clk", "adc_syn_gclk", 0,
- SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_ADC_CLK_ENB, 0,
- &_lock);
- clk_register_clkdev(clk, NULL, "adc_clk");
+ clk = clk_register_gate(NULL, "adc_clk", "adc_syn_gclk",
+ CLK_SET_RATE_PARENT, SPEAR1340_PERIP1_CLK_ENB,
+ SPEAR1340_ADC_CLK_ENB, 0, &_lock);
+ clk_register_clkdev(clk, NULL, "e0080000.adc");
/* clock derived from apb clk */
clk = clk_register_gate(NULL, "ssp_clk", "apb_clk", 0,
@@ -827,12 +878,12 @@ void __init spear1340_clk_init(void)
clk = clk_register_gate(NULL, "i2s_play_clk", "apb_clk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_I2S_PLAY_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "b2400000.i2s");
+ clk_register_clkdev(clk, NULL, "b2400000.i2s-play");
clk = clk_register_gate(NULL, "i2s_rec_clk", "apb_clk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_I2S_REC_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "b2000000.i2s");
+ clk_register_clkdev(clk, NULL, "b2000000.i2s-rec");
clk = clk_register_gate(NULL, "kbd_clk", "apb_clk", 0,
SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_KBD_CLK_ENB, 0,
@@ -844,37 +895,37 @@ void __init spear1340_clk_init(void)
ARRAY_SIZE(gen_synth0_1_parents), 0, SPEAR1340_PLL_CFG,
SPEAR1340_GEN_SYNT0_1_CLK_SHIFT,
SPEAR1340_GEN_SYNT_CLK_MASK, 0, &_lock);
- clk_register_clkdev(clk, "gen_syn0_1_clk", NULL);
+ clk_register_clkdev(clk, "gen_syn0_1_mclk", NULL);
clk = clk_register_mux(NULL, "gen_syn2_3_mclk", gen_synth2_3_parents,
ARRAY_SIZE(gen_synth2_3_parents), 0, SPEAR1340_PLL_CFG,
SPEAR1340_GEN_SYNT2_3_CLK_SHIFT,
SPEAR1340_GEN_SYNT_CLK_MASK, 0, &_lock);
- clk_register_clkdev(clk, "gen_syn2_3_clk", NULL);
+ clk_register_clkdev(clk, "gen_syn2_3_mclk", NULL);
- clk = clk_register_frac("gen_syn0_clk", "gen_syn0_1_clk", 0,
+ clk = clk_register_frac("gen_syn0_clk", "gen_syn0_1_mclk", 0,
SPEAR1340_GEN_CLK_SYNT0, gen_rtbl, ARRAY_SIZE(gen_rtbl),
&_lock);
clk_register_clkdev(clk, "gen_syn0_clk", NULL);
- clk = clk_register_frac("gen_syn1_clk", "gen_syn0_1_clk", 0,
+ clk = clk_register_frac("gen_syn1_clk", "gen_syn0_1_mclk", 0,
SPEAR1340_GEN_CLK_SYNT1, gen_rtbl, ARRAY_SIZE(gen_rtbl),
&_lock);
clk_register_clkdev(clk, "gen_syn1_clk", NULL);
- clk = clk_register_frac("gen_syn2_clk", "gen_syn2_3_clk", 0,
+ clk = clk_register_frac("gen_syn2_clk", "gen_syn2_3_mclk", 0,
SPEAR1340_GEN_CLK_SYNT2, gen_rtbl, ARRAY_SIZE(gen_rtbl),
&_lock);
clk_register_clkdev(clk, "gen_syn2_clk", NULL);
- clk = clk_register_frac("gen_syn3_clk", "gen_syn2_3_clk", 0,
+ clk = clk_register_frac("gen_syn3_clk", "gen_syn2_3_mclk", 0,
SPEAR1340_GEN_CLK_SYNT3, gen_rtbl, ARRAY_SIZE(gen_rtbl),
&_lock);
clk_register_clkdev(clk, "gen_syn3_clk", NULL);
- clk = clk_register_gate(NULL, "mali_clk", "gen_syn3_clk", 0,
- SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_MALI_CLK_ENB, 0,
- &_lock);
+ clk = clk_register_gate(NULL, "mali_clk", "gen_syn3_clk",
+ CLK_SET_RATE_PARENT, SPEAR1340_PERIP3_CLK_ENB,
+ SPEAR1340_MALI_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "mali");
clk = clk_register_gate(NULL, "cec0_clk", "ahb_clk", 0,
@@ -888,26 +939,26 @@ void __init spear1340_clk_init(void)
clk_register_clkdev(clk, NULL, "spear_cec.1");
clk = clk_register_mux(NULL, "spdif_out_mclk", spdif_out_parents,
- ARRAY_SIZE(spdif_out_parents), 0,
+ ARRAY_SIZE(spdif_out_parents), CLK_SET_RATE_PARENT,
SPEAR1340_PERIP_CLK_CFG, SPEAR1340_SPDIF_OUT_CLK_SHIFT,
SPEAR1340_SPDIF_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "spdif_out_mclk", NULL);
- clk = clk_register_gate(NULL, "spdif_out_clk", "spdif_out_mclk", 0,
- SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_SPDIF_OUT_CLK_ENB,
- 0, &_lock);
- clk_register_clkdev(clk, NULL, "spdif-out");
+ clk = clk_register_gate(NULL, "spdif_out_clk", "spdif_out_mclk",
+ CLK_SET_RATE_PARENT, SPEAR1340_PERIP3_CLK_ENB,
+ SPEAR1340_SPDIF_OUT_CLK_ENB, 0, &_lock);
+ clk_register_clkdev(clk, NULL, "d0000000.spdif-out");
clk = clk_register_mux(NULL, "spdif_in_mclk", spdif_in_parents,
- ARRAY_SIZE(spdif_in_parents), 0,
+ ARRAY_SIZE(spdif_in_parents), CLK_SET_RATE_PARENT,
SPEAR1340_PERIP_CLK_CFG, SPEAR1340_SPDIF_IN_CLK_SHIFT,
SPEAR1340_SPDIF_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "spdif_in_mclk", NULL);
- clk = clk_register_gate(NULL, "spdif_in_clk", "spdif_in_mclk", 0,
- SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_SPDIF_IN_CLK_ENB, 0,
- &_lock);
- clk_register_clkdev(clk, NULL, "spdif-in");
+ clk = clk_register_gate(NULL, "spdif_in_clk", "spdif_in_mclk",
+ CLK_SET_RATE_PARENT, SPEAR1340_PERIP3_CLK_ENB,
+ SPEAR1340_SPDIF_IN_CLK_ENB, 0, &_lock);
+ clk_register_clkdev(clk, NULL, "d0100000.spdif-in");
clk = clk_register_gate(NULL, "acp_clk", "acp_mclk", 0,
SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_ACP_CLK_ENB, 0,
@@ -917,7 +968,7 @@ void __init spear1340_clk_init(void)
clk = clk_register_gate(NULL, "plgpio_clk", "plgpio_mclk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_PLGPIO_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "plgpio");
+ clk_register_clkdev(clk, NULL, "e2800000.gpio");
clk = clk_register_gate(NULL, "video_dec_clk", "video_dec_mclk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_DEC_CLK_ENB,
@@ -937,25 +988,25 @@ void __init spear1340_clk_init(void)
clk = clk_register_gate(NULL, "cam0_clk", "cam0_mclk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM0_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "spear_camif.0");
+ clk_register_clkdev(clk, NULL, "d0200000.cam0");
clk = clk_register_gate(NULL, "cam1_clk", "cam1_mclk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM1_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "spear_camif.1");
+ clk_register_clkdev(clk, NULL, "d0300000.cam1");
clk = clk_register_gate(NULL, "cam2_clk", "cam2_mclk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM2_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "spear_camif.2");
+ clk_register_clkdev(clk, NULL, "d0400000.cam2");
clk = clk_register_gate(NULL, "cam3_clk", "cam3_mclk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM3_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "spear_camif.3");
+ clk_register_clkdev(clk, NULL, "d0500000.cam3");
- clk = clk_register_gate(NULL, "pwm_clk", "pwm_mclk", 0,
+ clk = clk_register_gate(NULL, "pwm_clk", "ahb_clk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_PWM_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "pwm");
+ clk_register_clkdev(clk, NULL, "e0180000.pwm");
}
diff --git a/drivers/clk/spear/spear3xx_clock.c b/drivers/clk/spear/spear3xx_clock.c
index c3157454bb3f..33d3ac588da7 100644
--- a/drivers/clk/spear/spear3xx_clock.c
+++ b/drivers/clk/spear/spear3xx_clock.c
@@ -107,6 +107,12 @@ static struct pll_rate_tbl pll_rtbl[] = {
/* aux rate configuration table, in ascending order of rates */
static struct aux_rate_tbl aux_rtbl[] = {
/* For PLL1 = 332 MHz */
+ {.xscale = 1, .yscale = 81, .eq = 0}, /* 2.049 MHz */
+ {.xscale = 1, .yscale = 59, .eq = 0}, /* 2.822 MHz */
+ {.xscale = 2, .yscale = 81, .eq = 0}, /* 4.098 MHz */
+ {.xscale = 3, .yscale = 89, .eq = 0}, /* 5.644 MHz */
+ {.xscale = 4, .yscale = 81, .eq = 0}, /* 8.197 MHz */
+ {.xscale = 4, .yscale = 59, .eq = 0}, /* 11.254 MHz */
{.xscale = 2, .yscale = 27, .eq = 0}, /* 12.296 MHz */
{.xscale = 2, .yscale = 8, .eq = 0}, /* 41.5 MHz */
{.xscale = 2, .yscale = 4, .eq = 0}, /* 83 MHz */
@@ -157,6 +163,8 @@ static void __init spear300_clk_init(void)
1);
clk_register_clkdev(clk, NULL, "a0000000.kbd");
}
+#else
+static inline void spear300_clk_init(void) { }
#endif
/* array of all spear 310 clock lookups */
@@ -197,6 +205,8 @@ static void __init spear310_clk_init(void)
1);
clk_register_clkdev(clk, NULL, "b2200000.serial");
}
+#else
+static inline void spear310_clk_init(void) { }
#endif
/* array of all spear 320 clock lookups */
@@ -251,7 +261,7 @@ static void __init spear320_clk_init(void)
clk = clk_register_fixed_factor(NULL, "pwm_clk", "ras_ahb_clk", 0, 1,
1);
- clk_register_clkdev(clk, "pwm", NULL);
+ clk_register_clkdev(clk, NULL, "a8000000.pwm");
clk = clk_register_fixed_factor(NULL, "ssp1_clk", "ras_ahb_clk", 0, 1,
1);
@@ -271,26 +281,37 @@ static void __init spear320_clk_init(void)
clk = clk_register_fixed_factor(NULL, "i2s_clk", "ras_apb_clk", 0, 1,
1);
- clk_register_clkdev(clk, NULL, "i2s");
+ clk_register_clkdev(clk, NULL, "a9400000.i2s");
clk = clk_register_mux(NULL, "i2s_ref_clk", i2s_ref_parents,
- ARRAY_SIZE(i2s_ref_parents), 0, SPEAR320_CONTROL_REG,
- I2S_REF_PCLK_SHIFT, I2S_REF_PCLK_MASK, 0, &_lock);
+ ARRAY_SIZE(i2s_ref_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_CONTROL_REG, I2S_REF_PCLK_SHIFT,
+ I2S_REF_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "i2s_ref_clk", NULL);
- clk = clk_register_fixed_factor(NULL, "i2s_sclk", "i2s_ref_clk", 0, 1,
+ clk = clk_register_fixed_factor(NULL, "i2s_sclk", "i2s_ref_clk",
+ CLK_SET_RATE_PARENT, 1,
4);
clk_register_clkdev(clk, "i2s_sclk", NULL);
+ clk = clk_register_fixed_factor(NULL, "macb1_clk", "ras_apb_clk", 0, 1,
+ 1);
+ clk_register_clkdev(clk, "hclk", "aa000000.eth");
+
+ clk = clk_register_fixed_factor(NULL, "macb2_clk", "ras_apb_clk", 0, 1,
+ 1);
+ clk_register_clkdev(clk, "hclk", "ab000000.eth");
+
clk = clk_register_mux(NULL, "rs485_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG,
- SPEAR320_RS485_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_EXT_CTRL_REG, SPEAR320_RS485_PCLK_SHIFT,
+ SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "a9300000.serial");
clk = clk_register_mux(NULL, "sdhci_clk", sdhci_parents,
- ARRAY_SIZE(sdhci_parents), 0, SPEAR320_CONTROL_REG,
- SDHCI_PCLK_SHIFT, SDHCI_PCLK_MASK, 0, &_lock);
+ ARRAY_SIZE(sdhci_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_CONTROL_REG, SDHCI_PCLK_SHIFT, SDHCI_PCLK_MASK,
+ 0, &_lock);
clk_register_clkdev(clk, NULL, "70000000.sdhci");
clk = clk_register_mux(NULL, "smii_pclk", smii0_parents,
@@ -302,49 +323,49 @@ static void __init spear320_clk_init(void)
clk_register_clkdev(clk, NULL, "smii");
clk = clk_register_mux(NULL, "uart1_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), 0, SPEAR320_CONTROL_REG,
- UART1_PCLK_SHIFT, UART1_PCLK_MASK, 0, &_lock);
+ ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_CONTROL_REG, UART1_PCLK_SHIFT, UART1_PCLK_MASK,
+ 0, &_lock);
clk_register_clkdev(clk, NULL, "a3000000.serial");
clk = clk_register_mux(NULL, "uart2_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG,
- SPEAR320_UART2_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_EXT_CTRL_REG, SPEAR320_UART2_PCLK_SHIFT,
+ SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "a4000000.serial");
clk = clk_register_mux(NULL, "uart3_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG,
- SPEAR320_UART3_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_EXT_CTRL_REG, SPEAR320_UART3_PCLK_SHIFT,
+ SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "a9100000.serial");
clk = clk_register_mux(NULL, "uart4_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG,
- SPEAR320_UART4_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_EXT_CTRL_REG, SPEAR320_UART4_PCLK_SHIFT,
+ SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "a9200000.serial");
clk = clk_register_mux(NULL, "uart5_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG,
- SPEAR320_UART5_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_EXT_CTRL_REG, SPEAR320_UART5_PCLK_SHIFT,
+ SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "60000000.serial");
clk = clk_register_mux(NULL, "uart6_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG,
- SPEAR320_UART6_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_EXT_CTRL_REG, SPEAR320_UART6_PCLK_SHIFT,
+ SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "60100000.serial");
}
+#else
+static inline void spear320_clk_init(void) { }
#endif
void __init spear3xx_clk_init(void)
{
struct clk *clk, *clk1;
- clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
- clk_register_clkdev(clk, "apb_pclk", NULL);
-
clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT,
32000);
clk_register_clkdev(clk, "osc_32k_clk", NULL);
@@ -380,7 +401,8 @@ void __init spear3xx_clk_init(void)
clk_register_clkdev(clk1, "pll2_clk", NULL);
/* clock derived from pll1 clk */
- clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", 0, 1, 1);
+ clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk",
+ CLK_SET_RATE_PARENT, 1, 1);
clk_register_clkdev(clk, "cpu_clk", NULL);
clk = clk_register_divider(NULL, "ahb_clk", "pll1_clk",
@@ -395,12 +417,14 @@ void __init spear3xx_clk_init(void)
clk_register_clkdev(clk1, "uart_syn_gclk", NULL);
clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents,
- ARRAY_SIZE(uart0_parents), 0, PERIP_CLK_CFG,
- UART_CLK_SHIFT, UART_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(uart0_parents), CLK_SET_RATE_PARENT,
+ PERIP_CLK_CFG, UART_CLK_SHIFT, UART_CLK_MASK, 0,
+ &_lock);
clk_register_clkdev(clk, "uart0_mclk", NULL);
- clk = clk_register_gate(NULL, "uart0", "uart0_mclk", 0, PERIP1_CLK_ENB,
- UART_CLK_ENB, 0, &_lock);
+ clk = clk_register_gate(NULL, "uart0", "uart0_mclk",
+ CLK_SET_RATE_PARENT, PERIP1_CLK_ENB, UART_CLK_ENB, 0,
+ &_lock);
clk_register_clkdev(clk, NULL, "d0000000.serial");
clk = clk_register_aux("firda_syn_clk", "firda_syn_gclk", "pll1_clk", 0,
@@ -410,40 +434,44 @@ void __init spear3xx_clk_init(void)
clk_register_clkdev(clk1, "firda_syn_gclk", NULL);
clk = clk_register_mux(NULL, "firda_mclk", firda_parents,
- ARRAY_SIZE(firda_parents), 0, PERIP_CLK_CFG,
- FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(firda_parents), CLK_SET_RATE_PARENT,
+ PERIP_CLK_CFG, FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0,
+ &_lock);
clk_register_clkdev(clk, "firda_mclk", NULL);
- clk = clk_register_gate(NULL, "firda_clk", "firda_mclk", 0,
- PERIP1_CLK_ENB, FIRDA_CLK_ENB, 0, &_lock);
+ clk = clk_register_gate(NULL, "firda_clk", "firda_mclk",
+ CLK_SET_RATE_PARENT, PERIP1_CLK_ENB, FIRDA_CLK_ENB, 0,
+ &_lock);
clk_register_clkdev(clk, NULL, "firda");
/* gpt clocks */
clk_register_gpt("gpt0_syn_clk", "pll1_clk", 0, PRSC0_CLK_CFG, gpt_rtbl,
ARRAY_SIZE(gpt_rtbl), &_lock);
clk = clk_register_mux(NULL, "gpt0_clk", gpt0_parents,
- ARRAY_SIZE(gpt0_parents), 0, PERIP_CLK_CFG,
- GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(gpt0_parents), CLK_SET_RATE_PARENT,
+ PERIP_CLK_CFG, GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "gpt0");
clk_register_gpt("gpt1_syn_clk", "pll1_clk", 0, PRSC1_CLK_CFG, gpt_rtbl,
ARRAY_SIZE(gpt_rtbl), &_lock);
clk = clk_register_mux(NULL, "gpt1_mclk", gpt1_parents,
- ARRAY_SIZE(gpt1_parents), 0, PERIP_CLK_CFG,
- GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(gpt1_parents), CLK_SET_RATE_PARENT,
+ PERIP_CLK_CFG, GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gpt1_mclk", NULL);
- clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", 0,
- PERIP1_CLK_ENB, GPT1_CLK_ENB, 0, &_lock);
+ clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk",
+ CLK_SET_RATE_PARENT, PERIP1_CLK_ENB, GPT1_CLK_ENB, 0,
+ &_lock);
clk_register_clkdev(clk, NULL, "gpt1");
clk_register_gpt("gpt2_syn_clk", "pll1_clk", 0, PRSC2_CLK_CFG, gpt_rtbl,
ARRAY_SIZE(gpt_rtbl), &_lock);
clk = clk_register_mux(NULL, "gpt2_mclk", gpt2_parents,
- ARRAY_SIZE(gpt2_parents), 0, PERIP_CLK_CFG,
- GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(gpt2_parents), CLK_SET_RATE_PARENT,
+ PERIP_CLK_CFG, GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gpt2_mclk", NULL);
- clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", 0,
- PERIP1_CLK_ENB, GPT2_CLK_ENB, 0, &_lock);
+ clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk",
+ CLK_SET_RATE_PARENT, PERIP1_CLK_ENB, GPT2_CLK_ENB, 0,
+ &_lock);
clk_register_clkdev(clk, NULL, "gpt2");
/* general synths clocks */
@@ -480,7 +508,9 @@ void __init spear3xx_clk_init(void)
/* clock derived from pll3 clk */
clk = clk_register_gate(NULL, "usbh_clk", "pll3_clk", 0, PERIP1_CLK_ENB,
USBH_CLK_ENB, 0, &_lock);
- clk_register_clkdev(clk, "usbh_clk", NULL);
+ clk_register_clkdev(clk, NULL, "e1800000.ehci");
+ clk_register_clkdev(clk, NULL, "e1900000.ohci");
+ clk_register_clkdev(clk, NULL, "e2100000.ohci");
clk = clk_register_fixed_factor(NULL, "usbh.0_clk", "usbh_clk", 0, 1,
1);
@@ -492,7 +522,7 @@ void __init spear3xx_clk_init(void)
clk = clk_register_gate(NULL, "usbd_clk", "pll3_clk", 0, PERIP1_CLK_ENB,
USBD_CLK_ENB, 0, &_lock);
- clk_register_clkdev(clk, NULL, "designware_udc");
+ clk_register_clkdev(clk, NULL, "e1100000.usbd");
/* clock derived from ahb clk */
clk = clk_register_fixed_factor(NULL, "ahbmult2_clk", "ahb_clk", 0, 2,
@@ -540,7 +570,7 @@ void __init spear3xx_clk_init(void)
/* clock derived from apb clk */
clk = clk_register_gate(NULL, "adc_clk", "apb_clk", 0, PERIP1_CLK_ENB,
ADC_CLK_ENB, 0, &_lock);
- clk_register_clkdev(clk, NULL, "adc");
+ clk_register_clkdev(clk, NULL, "d0080000.adc");
clk = clk_register_gate(NULL, "gpio0_clk", "apb_clk", 0, PERIP1_CLK_ENB,
GPIO_CLK_ENB, 0, &_lock);
@@ -579,20 +609,24 @@ void __init spear3xx_clk_init(void)
RAS_CLK_ENB, RAS_48M_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, "ras_pll3_clk", NULL);
- clk = clk_register_gate(NULL, "ras_syn0_gclk", "gen0_syn_gclk", 0,
- RAS_CLK_ENB, RAS_SYNT0_CLK_ENB, 0, &_lock);
+ clk = clk_register_gate(NULL, "ras_syn0_gclk", "gen0_syn_gclk",
+ CLK_SET_RATE_PARENT, RAS_CLK_ENB, RAS_SYNT0_CLK_ENB, 0,
+ &_lock);
clk_register_clkdev(clk, "ras_syn0_gclk", NULL);
- clk = clk_register_gate(NULL, "ras_syn1_gclk", "gen1_syn_gclk", 0,
- RAS_CLK_ENB, RAS_SYNT1_CLK_ENB, 0, &_lock);
+ clk = clk_register_gate(NULL, "ras_syn1_gclk", "gen1_syn_gclk",
+ CLK_SET_RATE_PARENT, RAS_CLK_ENB, RAS_SYNT1_CLK_ENB, 0,
+ &_lock);
clk_register_clkdev(clk, "ras_syn1_gclk", NULL);
- clk = clk_register_gate(NULL, "ras_syn2_gclk", "gen2_syn_gclk", 0,
- RAS_CLK_ENB, RAS_SYNT2_CLK_ENB, 0, &_lock);
+ clk = clk_register_gate(NULL, "ras_syn2_gclk", "gen2_syn_gclk",
+ CLK_SET_RATE_PARENT, RAS_CLK_ENB, RAS_SYNT2_CLK_ENB, 0,
+ &_lock);
clk_register_clkdev(clk, "ras_syn2_gclk", NULL);
- clk = clk_register_gate(NULL, "ras_syn3_gclk", "gen3_syn_gclk", 0,
- RAS_CLK_ENB, RAS_SYNT3_CLK_ENB, 0, &_lock);
+ clk = clk_register_gate(NULL, "ras_syn3_gclk", "gen3_syn_gclk",
+ CLK_SET_RATE_PARENT, RAS_CLK_ENB, RAS_SYNT3_CLK_ENB, 0,
+ &_lock);
clk_register_clkdev(clk, "ras_syn3_gclk", NULL);
if (of_machine_is_compatible("st,spear300"))
diff --git a/drivers/clk/spear/spear6xx_clock.c b/drivers/clk/spear/spear6xx_clock.c
index a98d0866f541..e862a333ad30 100644
--- a/drivers/clk/spear/spear6xx_clock.c
+++ b/drivers/clk/spear/spear6xx_clock.c
@@ -92,6 +92,7 @@ static struct pll_rate_tbl pll_rtbl[] = {
/* aux rate configuration table, in ascending order of rates */
static struct aux_rate_tbl aux_rtbl[] = {
/* For PLL1 = 332 MHz */
+ {.xscale = 2, .yscale = 27, .eq = 0}, /* 12.296 MHz */
{.xscale = 2, .yscale = 8, .eq = 0}, /* 41.5 MHz */
{.xscale = 2, .yscale = 4, .eq = 0}, /* 83 MHz */
{.xscale = 1, .yscale = 2, .eq = 1}, /* 166 MHz */
@@ -118,9 +119,6 @@ void __init spear6xx_clk_init(void)
{
struct clk *clk, *clk1;
- clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
- clk_register_clkdev(clk, "apb_pclk", NULL);
-
clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT,
32000);
clk_register_clkdev(clk, "osc_32k_clk", NULL);
@@ -156,7 +154,8 @@ void __init spear6xx_clk_init(void)
clk_register_clkdev(clk, NULL, "wdt");
/* clock derived from pll1 clk */
- clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", 0, 1, 1);
+ clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk",
+ CLK_SET_RATE_PARENT, 1, 1);
clk_register_clkdev(clk, "cpu_clk", NULL);
clk = clk_register_divider(NULL, "ahb_clk", "pll1_clk",
@@ -261,11 +260,13 @@ void __init spear6xx_clk_init(void)
/* clock derived from pll3 clk */
clk = clk_register_gate(NULL, "usbh0_clk", "pll3_clk", 0,
PERIP1_CLK_ENB, USBH0_CLK_ENB, 0, &_lock);
- clk_register_clkdev(clk, NULL, "usbh.0_clk");
+ clk_register_clkdev(clk, NULL, "e1800000.ehci");
+ clk_register_clkdev(clk, NULL, "e1900000.ohci");
clk = clk_register_gate(NULL, "usbh1_clk", "pll3_clk", 0,
PERIP1_CLK_ENB, USBH1_CLK_ENB, 0, &_lock);
- clk_register_clkdev(clk, NULL, "usbh.1_clk");
+ clk_register_clkdev(clk, NULL, "e2000000.ehci");
+ clk_register_clkdev(clk, NULL, "e2100000.ohci");
clk = clk_register_gate(NULL, "usbd_clk", "pll3_clk", 0, PERIP1_CLK_ENB,
USBD_CLK_ENB, 0, &_lock);
diff --git a/drivers/clk/ux500/Makefile b/drivers/clk/ux500/Makefile
index 858fbfe66281..bcc0c11a507c 100644
--- a/drivers/clk/ux500/Makefile
+++ b/drivers/clk/ux500/Makefile
@@ -10,3 +10,6 @@ obj-y += clk-prcmu.o
obj-y += u8500_clk.o
obj-y += u9540_clk.o
obj-y += u8540_clk.o
+
+# ABX500 clock driver
+obj-y += abx500-clk.o
diff --git a/drivers/clk/ux500/abx500-clk.c b/drivers/clk/ux500/abx500-clk.c
new file mode 100644
index 000000000000..e27c52317ffe
--- /dev/null
+++ b/drivers/clk/ux500/abx500-clk.c
@@ -0,0 +1,73 @@
+/*
+ * abx500 clock implementation for ux500 platform.
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/abx500/ab8500.h>
+
+/* TODO: Add clock implementations here */
+
+
+/* Clock definitions for ab8500 */
+static int ab8500_reg_clks(struct device *dev)
+{
+ return 0;
+}
+
+/* Clock definitions for ab8540 */
+static int ab8540_reg_clks(struct device *dev)
+{
+ return 0;
+}
+
+/* Clock definitions for ab9540 */
+static int ab9540_reg_clks(struct device *dev)
+{
+ return 0;
+}
+
+static int __devinit abx500_clk_probe(struct platform_device *pdev)
+{
+ struct ab8500 *parent = dev_get_drvdata(pdev->dev.parent);
+ int ret;
+
+ if (is_ab8500(parent) || is_ab8505(parent)) {
+ ret = ab8500_reg_clks(&pdev->dev);
+ } else if (is_ab8540(parent)) {
+ ret = ab8540_reg_clks(&pdev->dev);
+ } else if (is_ab9540(parent)) {
+ ret = ab9540_reg_clks(&pdev->dev);
+ } else {
+ dev_err(&pdev->dev, "non supported plf id\n");
+ return -ENODEV;
+ }
+
+ return ret;
+}
+
+static struct platform_driver abx500_clk_driver = {
+ .driver = {
+ .name = "abx500-clk",
+ .owner = THIS_MODULE,
+ },
+ .probe = abx500_clk_probe,
+};
+
+static int __init abx500_clk_init(void)
+{
+ return platform_driver_register(&abx500_clk_driver);
+}
+
+arch_initcall(abx500_clk_init);
+
+MODULE_AUTHOR("Ulf Hansson <ulf.hansson@linaro.org");
+MODULE_DESCRIPTION("ABX500 clk driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c
index 930cdfeb47ab..74faa7e3cf59 100644
--- a/drivers/clk/ux500/clk-prcmu.c
+++ b/drivers/clk/ux500/clk-prcmu.c
@@ -133,6 +133,40 @@ out_error:
hw->init->name);
}
+static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)
+{
+ int err;
+ struct clk_prcmu *clk = to_clk_prcmu(hw);
+
+ err = prcmu_request_ape_opp_100_voltage(true);
+ if (err) {
+ pr_err("clk_prcmu: %s failed to request APE OPP VOLT for %s.\n",
+ __func__, hw->init->name);
+ return err;
+ }
+
+ err = prcmu_request_clock(clk->cg_sel, true);
+ if (err)
+ prcmu_request_ape_opp_100_voltage(false);
+
+ return err;
+}
+
+static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw)
+{
+ struct clk_prcmu *clk = to_clk_prcmu(hw);
+
+ if (prcmu_request_clock(clk->cg_sel, false))
+ goto out_error;
+ if (prcmu_request_ape_opp_100_voltage(false))
+ goto out_error;
+ return;
+
+out_error:
+ pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
+ hw->init->name);
+}
+
static struct clk_ops clk_prcmu_scalable_ops = {
.prepare = clk_prcmu_prepare,
.unprepare = clk_prcmu_unprepare,
@@ -153,6 +187,13 @@ static struct clk_ops clk_prcmu_gate_ops = {
.recalc_rate = clk_prcmu_recalc_rate,
};
+static struct clk_ops clk_prcmu_scalable_rate_ops = {
+ .is_enabled = clk_prcmu_is_enabled,
+ .recalc_rate = clk_prcmu_recalc_rate,
+ .round_rate = clk_prcmu_round_rate,
+ .set_rate = clk_prcmu_set_rate,
+};
+
static struct clk_ops clk_prcmu_rate_ops = {
.is_enabled = clk_prcmu_is_enabled,
.recalc_rate = clk_prcmu_recalc_rate,
@@ -167,6 +208,17 @@ static struct clk_ops clk_prcmu_opp_gate_ops = {
.recalc_rate = clk_prcmu_recalc_rate,
};
+static struct clk_ops clk_prcmu_opp_volt_scalable_ops = {
+ .prepare = clk_prcmu_opp_volt_prepare,
+ .unprepare = clk_prcmu_opp_volt_unprepare,
+ .enable = clk_prcmu_enable,
+ .disable = clk_prcmu_disable,
+ .is_enabled = clk_prcmu_is_enabled,
+ .recalc_rate = clk_prcmu_recalc_rate,
+ .round_rate = clk_prcmu_round_rate,
+ .set_rate = clk_prcmu_set_rate,
+};
+
static struct clk *clk_reg_prcmu(const char *name,
const char *parent_name,
u8 cg_sel,
@@ -233,6 +285,16 @@ struct clk *clk_reg_prcmu_gate(const char *name,
&clk_prcmu_gate_ops);
}
+struct clk *clk_reg_prcmu_scalable_rate(const char *name,
+ const char *parent_name,
+ u8 cg_sel,
+ unsigned long rate,
+ unsigned long flags)
+{
+ return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
+ &clk_prcmu_scalable_rate_ops);
+}
+
struct clk *clk_reg_prcmu_rate(const char *name,
const char *parent_name,
u8 cg_sel,
@@ -250,3 +312,13 @@ struct clk *clk_reg_prcmu_opp_gate(const char *name,
return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
&clk_prcmu_opp_gate_ops);
}
+
+struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name,
+ const char *parent_name,
+ u8 cg_sel,
+ unsigned long rate,
+ unsigned long flags)
+{
+ return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
+ &clk_prcmu_opp_volt_scalable_ops);
+}
diff --git a/drivers/clk/ux500/clk.h b/drivers/clk/ux500/clk.h
index 836d7d16751e..c3e449169a83 100644
--- a/drivers/clk/ux500/clk.h
+++ b/drivers/clk/ux500/clk.h
@@ -35,6 +35,12 @@ struct clk *clk_reg_prcmu_gate(const char *name,
u8 cg_sel,
unsigned long flags);
+struct clk *clk_reg_prcmu_scalable_rate(const char *name,
+ const char *parent_name,
+ u8 cg_sel,
+ unsigned long rate,
+ unsigned long flags);
+
struct clk *clk_reg_prcmu_rate(const char *name,
const char *parent_name,
u8 cg_sel,
@@ -45,4 +51,10 @@ struct clk *clk_reg_prcmu_opp_gate(const char *name,
u8 cg_sel,
unsigned long flags);
+struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name,
+ const char *parent_name,
+ u8 cg_sel,
+ unsigned long rate,
+ unsigned long flags);
+
#endif /* __UX500_CLK_H */
diff --git a/drivers/clk/ux500/u8500_clk.c b/drivers/clk/ux500/u8500_clk.c
index e2c17d187d98..7d0e0258f204 100644
--- a/drivers/clk/ux500/u8500_clk.c
+++ b/drivers/clk/ux500/u8500_clk.c
@@ -170,10 +170,11 @@ void u8500_clk_init(void)
clk_register_clkdev(clk, NULL, "mtu0");
clk_register_clkdev(clk, NULL, "mtu1");
- clk = clk_reg_prcmu_gate("sdmmcclk", NULL, PRCMU_SDMMCCLK, CLK_IS_ROOT);
+ clk = clk_reg_prcmu_opp_volt_scalable("sdmmcclk", NULL, PRCMU_SDMMCCLK,
+ 100000000,
+ CLK_IS_ROOT|CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "sdmmc");
-
clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk",
PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE);
clk_register_clkdev(clk, "dsihs2", "mcde");
@@ -205,16 +206,18 @@ void u8500_clk_init(void)
clk_register_clkdev(clk, "dsilp2", "dsilink.2");
clk_register_clkdev(clk, "dsilp2", "mcde");
- clk = clk_reg_prcmu_rate("smp_twd", NULL, PRCMU_ARMSS,
- CLK_IS_ROOT|CLK_GET_RATE_NOCACHE|
- CLK_IGNORE_UNUSED);
+ clk = clk_reg_prcmu_scalable_rate("armss", NULL,
+ PRCMU_ARMSS, 0, CLK_IS_ROOT|CLK_IGNORE_UNUSED);
+ clk_register_clkdev(clk, "armss", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "smp_twd", "armss",
+ CLK_IGNORE_UNUSED, 1, 2);
clk_register_clkdev(clk, NULL, "smp_twd");
/*
* FIXME: Add special handled PRCMU clocks here:
- * 1. clk_arm, use PRCMU_ARMCLK.
- * 2. clkout0yuv, use PRCMU as parent + need regulator + pinctrl.
- * 3. ab9540_clkout1yuv, see clkout0yuv
+ * 1. clkout0yuv, use PRCMU as parent + need regulator + pinctrl.
+ * 2. ab9540_clkout1yuv, see clkout0yuv
*/
/* PRCC P-clocks */
@@ -323,7 +326,7 @@ void u8500_clk_init(void)
clk_register_clkdev(clk, NULL, "gpioblock1");
clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", U8500_CLKRST2_BASE,
- BIT(11), 0);
+ BIT(12), 0);
clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", U8500_CLKRST3_BASE,
BIT(0), 0);
@@ -347,6 +350,8 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", U8500_CLKRST3_BASE,
BIT(5), 0);
+ clk_register_clkdev(clk, "apb_pclk", "ske");
+ clk_register_clkdev(clk, "apb_pclk", "nmk-ske-keypad");
clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", U8500_CLKRST3_BASE,
BIT(6), 0);
@@ -375,6 +380,7 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", U8500_CLKRST6_BASE,
BIT(0), 0);
+ clk_register_clkdev(clk, "apb_pclk", "rng");
clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", U8500_CLKRST6_BASE,
BIT(1), 0);
@@ -503,6 +509,8 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k",
U8500_CLKRST3_BASE, BIT(5), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "ske");
+ clk_register_clkdev(clk, NULL, "nmk-ske-keypad");
clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk",
U8500_CLKRST3_BASE, BIT(6), CLK_SET_RATE_GATE);
@@ -515,5 +523,5 @@ void u8500_clk_init(void)
/* Periph6 */
clk = clk_reg_prcc_kclk("p3_rng_kclk", "rngclk",
U8500_CLKRST6_BASE, BIT(0), CLK_SET_RATE_GATE);
-
+ clk_register_clkdev(clk, NULL, "rng");
}
diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile
index c0a0f6478798..ec3b88fe3e6d 100644
--- a/drivers/clk/versatile/Makefile
+++ b/drivers/clk/versatile/Makefile
@@ -1,4 +1,7 @@
# Makefile for Versatile-specific clocks
obj-$(CONFIG_ICST) += clk-icst.o
obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o
+obj-$(CONFIG_INTEGRATOR_IMPD1) += clk-impd1.o
obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o
+obj-$(CONFIG_ARCH_VEXPRESS) += clk-vexpress.o
+obj-$(CONFIG_VEXPRESS_CONFIG) += clk-vexpress-osc.o
diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c
index f555b50a5fa5..67ccf4aa7277 100644
--- a/drivers/clk/versatile/clk-icst.c
+++ b/drivers/clk/versatile/clk-icst.c
@@ -3,6 +3,12 @@
* We wrap the custom interface from <asm/hardware/icst.h> into the generic
* clock framework.
*
+ * Copyright (C) 2012 Linus Walleij
+ *
+ * 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.
+ *
* TODO: when all ARM reference designs are migrated to generic clocks, the
* ICST clock code from the ARM tree should probably be merged into this
* file.
@@ -11,33 +17,74 @@
#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/clk-provider.h>
+#include <linux/io.h>
#include "clk-icst.h"
/**
* struct clk_icst - ICST VCO clock wrapper
* @hw: corresponding clock hardware entry
+ * @vcoreg: VCO register address
+ * @lockreg: VCO lock register address
* @params: parameters for this ICST instance
* @rate: current rate
- * @setvco: function to commit ICST settings to hardware
*/
struct clk_icst {
struct clk_hw hw;
+ void __iomem *vcoreg;
+ void __iomem *lockreg;
const struct icst_params *params;
unsigned long rate;
- struct icst_vco (*getvco)(void);
- void (*setvco)(struct icst_vco);
};
#define to_icst(_hw) container_of(_hw, struct clk_icst, hw)
+/**
+ * vco_get() - get ICST VCO settings from a certain register
+ * @vcoreg: register containing the VCO settings
+ */
+static struct icst_vco vco_get(void __iomem *vcoreg)
+{
+ u32 val;
+ struct icst_vco vco;
+
+ val = readl(vcoreg);
+ vco.v = val & 0x1ff;
+ vco.r = (val >> 9) & 0x7f;
+ vco.s = (val >> 16) & 03;
+ return vco;
+}
+
+/**
+ * vco_set() - commit changes to an ICST VCO
+ * @locreg: register to poke to unlock the VCO for writing
+ * @vcoreg: register containing the VCO settings
+ * @vco: ICST VCO parameters to commit
+ */
+static void vco_set(void __iomem *lockreg,
+ void __iomem *vcoreg,
+ struct icst_vco vco)
+{
+ u32 val;
+
+ val = readl(vcoreg) & ~0x7ffff;
+ val |= vco.v | (vco.r << 9) | (vco.s << 16);
+
+ /* This magic unlocks the VCO so it can be controlled */
+ writel(0xa05f, lockreg);
+ writel(val, vcoreg);
+ /* This locks the VCO again */
+ writel(0, lockreg);
+}
+
+
static unsigned long icst_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_icst *icst = to_icst(hw);
struct icst_vco vco;
- vco = icst->getvco();
+ vco = vco_get(icst->vcoreg);
icst->rate = icst_hz(icst->params, vco);
return icst->rate;
}
@@ -60,7 +107,7 @@ static int icst_set_rate(struct clk_hw *hw, unsigned long rate,
vco = icst_hz_to_vco(icst->params, rate);
icst->rate = icst_hz(icst->params, vco);
- icst->setvco(vco);
+ vco_set(icst->vcoreg, icst->lockreg, vco);
return 0;
}
@@ -70,8 +117,9 @@ static const struct clk_ops icst_ops = {
.set_rate = icst_set_rate,
};
-struct clk * __init icst_clk_register(struct device *dev,
- const struct clk_icst_desc *desc)
+struct clk *icst_clk_register(struct device *dev,
+ const struct clk_icst_desc *desc,
+ void __iomem *base)
{
struct clk *clk;
struct clk_icst *icst;
@@ -89,8 +137,8 @@ struct clk * __init icst_clk_register(struct device *dev,
init.num_parents = 0;
icst->hw.init = &init;
icst->params = desc->params;
- icst->getvco = desc->getvco;
- icst->setvco = desc->setvco;
+ icst->vcoreg = base + desc->vco_offset;
+ icst->lockreg = base + desc->lock_offset;
clk = clk_register(dev, &icst->hw);
if (IS_ERR(clk))
diff --git a/drivers/clk/versatile/clk-icst.h b/drivers/clk/versatile/clk-icst.h
index 71b4c56c1410..dad51b6ffd00 100644
--- a/drivers/clk/versatile/clk-icst.h
+++ b/drivers/clk/versatile/clk-icst.h
@@ -1,10 +1,18 @@
#include <asm/hardware/icst.h>
+/**
+ * struct clk_icst_desc - descriptor for the ICST VCO
+ * @params: ICST parameters
+ * @vco_offset: offset to the ICST VCO from the provided memory base
+ * @lock_offset: offset to the ICST VCO locking register from the provided
+ * memory base
+ */
struct clk_icst_desc {
const struct icst_params *params;
- struct icst_vco (*getvco)(void);
- void (*setvco)(struct icst_vco);
+ u32 vco_offset;
+ u32 lock_offset;
};
struct clk *icst_clk_register(struct device *dev,
- const struct clk_icst_desc *desc);
+ const struct clk_icst_desc *desc,
+ void __iomem *base);
diff --git a/drivers/clk/versatile/clk-impd1.c b/drivers/clk/versatile/clk-impd1.c
new file mode 100644
index 000000000000..369139af2a3b
--- /dev/null
+++ b/drivers/clk/versatile/clk-impd1.c
@@ -0,0 +1,97 @@
+/*
+ * Clock driver for the ARM Integrator/IM-PD1 board
+ * Copyright (C) 2012 Linus Walleij
+ *
+ * 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/clk-provider.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_data/clk-integrator.h>
+
+#include <mach/impd1.h>
+
+#include "clk-icst.h"
+
+struct impd1_clk {
+ struct clk *vcoclk;
+ struct clk *uartclk;
+ struct clk_lookup *clks[3];
+};
+
+static struct impd1_clk impd1_clks[4];
+
+/*
+ * There are two VCO's on the IM-PD1 but only one is used by the
+ * kernel, that is why we are only implementing the control of
+ * IMPD1_OSC1 here.
+ */
+
+static const struct icst_params impd1_vco_params = {
+ .ref = 24000000, /* 24 MHz */
+ .vco_max = ICST525_VCO_MAX_3V,
+ .vco_min = ICST525_VCO_MIN,
+ .vd_min = 12,
+ .vd_max = 519,
+ .rd_min = 3,
+ .rd_max = 120,
+ .s2div = icst525_s2div,
+ .idx2s = icst525_idx2s,
+};
+
+static const struct clk_icst_desc impd1_icst1_desc = {
+ .params = &impd1_vco_params,
+ .vco_offset = IMPD1_OSC1,
+ .lock_offset = IMPD1_LOCK,
+};
+
+/**
+ * integrator_impd1_clk_init() - set up the integrator clock tree
+ * @base: base address of the logic module (LM)
+ * @id: the ID of this LM
+ */
+void integrator_impd1_clk_init(void __iomem *base, unsigned int id)
+{
+ struct impd1_clk *imc;
+ struct clk *clk;
+ int i;
+
+ if (id > 3) {
+ pr_crit("no more than 4 LMs can be attached\n");
+ return;
+ }
+ imc = &impd1_clks[id];
+
+ clk = icst_clk_register(NULL, &impd1_icst1_desc, base);
+ imc->vcoclk = clk;
+ imc->clks[0] = clkdev_alloc(clk, NULL, "lm%x:01000", id);
+
+ /* UART reference clock */
+ clk = clk_register_fixed_rate(NULL, "uartclk", NULL, CLK_IS_ROOT,
+ 14745600);
+ imc->uartclk = clk;
+ imc->clks[1] = clkdev_alloc(clk, NULL, "lm%x:00100", id);
+ imc->clks[2] = clkdev_alloc(clk, NULL, "lm%x:00200", id);
+
+ for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
+ clkdev_add(imc->clks[i]);
+}
+
+void integrator_impd1_clk_exit(unsigned int id)
+{
+ int i;
+ struct impd1_clk *imc;
+
+ if (id > 3)
+ return;
+ imc = &impd1_clks[id];
+
+ for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
+ clkdev_drop(imc->clks[i]);
+ clk_unregister(imc->uartclk);
+ clk_unregister(imc->vcoclk);
+}
diff --git a/drivers/clk/versatile/clk-integrator.c b/drivers/clk/versatile/clk-integrator.c
index a5053921bf7f..08593b4ee2c9 100644
--- a/drivers/clk/versatile/clk-integrator.c
+++ b/drivers/clk/versatile/clk-integrator.c
@@ -1,8 +1,16 @@
+/*
+ * Clock driver for the ARM Integrator/AP and Integrator/CP boards
+ * Copyright (C) 2012 Linus Walleij
+ *
+ * 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/clk-provider.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/clk-provider.h>
+#include <linux/platform_data/clk-integrator.h>
#include <mach/hardware.h>
#include <mach/platform.h>
@@ -14,42 +22,6 @@
* Inspired by portions of:
* plat-versatile/clock.c and plat-versatile/include/plat/clock.h
*/
-#define CM_LOCK (__io_address(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET)
-#define CM_AUXOSC (__io_address(INTEGRATOR_HDR_BASE)+0x1c)
-
-/**
- * cp_auxvco_get() - get ICST VCO settings for the Integrator/CP
- * @vco: ICST VCO parameters to update with hardware status
- */
-static struct icst_vco cp_auxvco_get(void)
-{
- u32 val;
- struct icst_vco vco;
-
- val = readl(CM_AUXOSC);
- vco.v = val & 0x1ff;
- vco.r = (val >> 9) & 0x7f;
- vco.s = (val >> 16) & 03;
- return vco;
-}
-
-/**
- * cp_auxvco_set() - commit changes to Integrator/CP ICST VCO
- * @vco: ICST VCO parameters to commit
- */
-static void cp_auxvco_set(struct icst_vco vco)
-{
- u32 val;
-
- val = readl(CM_AUXOSC) & ~0x7ffff;
- val |= vco.v | (vco.r << 9) | (vco.s << 16);
-
- /* This magic unlocks the CM VCO so it can be controlled */
- writel(0xa05f, CM_LOCK);
- writel(val, CM_AUXOSC);
- /* This locks the CM again */
- writel(0, CM_LOCK);
-}
static const struct icst_params cp_auxvco_params = {
.ref = 24000000,
@@ -65,8 +37,8 @@ static const struct icst_params cp_auxvco_params = {
static const struct clk_icst_desc __initdata cp_icst_desc = {
.params = &cp_auxvco_params,
- .getvco = cp_auxvco_get,
- .setvco = cp_auxvco_set,
+ .vco_offset = 0x1c,
+ .lock_offset = INTEGRATOR_HDR_LOCK_OFFSET,
};
/*
@@ -106,6 +78,7 @@ void __init integrator_clk_init(bool is_cp)
clk_register_clkdev(clk, NULL, "sp804");
/* ICST VCO clock used on the Integrator/CP CLCD */
- clk = icst_clk_register(NULL, &cp_icst_desc);
+ clk = icst_clk_register(NULL, &cp_icst_desc,
+ __io_address(INTEGRATOR_HDR_BASE));
clk_register_clkdev(clk, NULL, "clcd");
}
diff --git a/drivers/clk/versatile/clk-realview.c b/drivers/clk/versatile/clk-realview.c
index e21a99cef378..cda07e70a408 100644
--- a/drivers/clk/versatile/clk-realview.c
+++ b/drivers/clk/versatile/clk-realview.c
@@ -1,3 +1,11 @@
+/*
+ * Clock driver for the ARM RealView boards
+ * Copyright (C) 2012 Linus Walleij
+ *
+ * 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/clk.h>
#include <linux/clkdev.h>
#include <linux/err.h>
@@ -13,38 +21,6 @@
* Implementation of the ARM RealView clock trees.
*/
-static void __iomem *sys_lock;
-static void __iomem *sys_vcoreg;
-
-/**
- * realview_oscvco_get() - get ICST OSC settings for the RealView
- */
-static struct icst_vco realview_oscvco_get(void)
-{
- u32 val;
- struct icst_vco vco;
-
- val = readl(sys_vcoreg);
- vco.v = val & 0x1ff;
- vco.r = (val >> 9) & 0x7f;
- vco.s = (val >> 16) & 03;
- return vco;
-}
-
-static void realview_oscvco_set(struct icst_vco vco)
-{
- u32 val;
-
- val = readl(sys_vcoreg) & ~0x7ffff;
- val |= vco.v | (vco.r << 9) | (vco.s << 16);
-
- /* This magic unlocks the CM VCO so it can be controlled */
- writel(0xa05f, sys_lock);
- writel(val, sys_vcoreg);
- /* This locks the CM again */
- writel(0, sys_lock);
-}
-
static const struct icst_params realview_oscvco_params = {
.ref = 24000000,
.vco_max = ICST307_VCO_MAX,
@@ -57,10 +33,16 @@ static const struct icst_params realview_oscvco_params = {
.idx2s = icst307_idx2s,
};
-static const struct clk_icst_desc __initdata realview_icst_desc = {
+static const struct clk_icst_desc __initdata realview_osc0_desc = {
+ .params = &realview_oscvco_params,
+ .vco_offset = REALVIEW_SYS_OSC0_OFFSET,
+ .lock_offset = REALVIEW_SYS_LOCK_OFFSET,
+};
+
+static const struct clk_icst_desc __initdata realview_osc4_desc = {
.params = &realview_oscvco_params,
- .getvco = realview_oscvco_get,
- .setvco = realview_oscvco_set,
+ .vco_offset = REALVIEW_SYS_OSC4_OFFSET,
+ .lock_offset = REALVIEW_SYS_LOCK_OFFSET,
};
/*
@@ -70,13 +52,6 @@ void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176)
{
struct clk *clk;
- sys_lock = sysbase + REALVIEW_SYS_LOCK_OFFSET;
- if (is_pb1176)
- sys_vcoreg = sysbase + REALVIEW_SYS_OSC0_OFFSET;
- else
- sys_vcoreg = sysbase + REALVIEW_SYS_OSC4_OFFSET;
-
-
/* APB clock dummy */
clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
clk_register_clkdev(clk, "apb_pclk", NULL);
@@ -108,7 +83,11 @@ void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176)
clk_register_clkdev(clk, NULL, "sp804");
/* ICST VCO clock */
- clk = icst_clk_register(NULL, &realview_icst_desc);
+ if (is_pb1176)
+ clk = icst_clk_register(NULL, &realview_osc0_desc, sysbase);
+ else
+ clk = icst_clk_register(NULL, &realview_osc4_desc, sysbase);
+
clk_register_clkdev(clk, NULL, "dev:clcd");
clk_register_clkdev(clk, NULL, "issp:clcd");
}
diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c
new file mode 100644
index 000000000000..dcb6ae0a0425
--- /dev/null
+++ b/drivers/clk/versatile/clk-vexpress-osc.c
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2012 ARM Limited
+ */
+
+#define pr_fmt(fmt) "vexpress-osc: " fmt
+
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/vexpress.h>
+
+struct vexpress_osc {
+ struct vexpress_config_func *func;
+ struct clk_hw hw;
+ unsigned long rate_min;
+ unsigned long rate_max;
+};
+
+#define to_vexpress_osc(osc) container_of(osc, struct vexpress_osc, hw)
+
+static unsigned long vexpress_osc_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct vexpress_osc *osc = to_vexpress_osc(hw);
+ u32 rate;
+
+ vexpress_config_read(osc->func, 0, &rate);
+
+ return rate;
+}
+
+static long vexpress_osc_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct vexpress_osc *osc = to_vexpress_osc(hw);
+
+ if (WARN_ON(osc->rate_min && rate < osc->rate_min))
+ rate = osc->rate_min;
+
+ if (WARN_ON(osc->rate_max && rate > osc->rate_max))
+ rate = osc->rate_max;
+
+ return rate;
+}
+
+static int vexpress_osc_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct vexpress_osc *osc = to_vexpress_osc(hw);
+
+ return vexpress_config_write(osc->func, 0, rate);
+}
+
+static struct clk_ops vexpress_osc_ops = {
+ .recalc_rate = vexpress_osc_recalc_rate,
+ .round_rate = vexpress_osc_round_rate,
+ .set_rate = vexpress_osc_set_rate,
+};
+
+
+struct clk * __init vexpress_osc_setup(struct device *dev)
+{
+ struct clk_init_data init;
+ struct vexpress_osc *osc = kzalloc(sizeof(*osc), GFP_KERNEL);
+
+ if (!osc)
+ return NULL;
+
+ osc->func = vexpress_config_func_get_by_dev(dev);
+ if (!osc->func) {
+ kfree(osc);
+ return NULL;
+ }
+
+ init.name = dev_name(dev);
+ init.ops = &vexpress_osc_ops;
+ init.flags = CLK_IS_ROOT;
+ init.num_parents = 0;
+ osc->hw.init = &init;
+
+ return clk_register(NULL, &osc->hw);
+}
+
+void __init vexpress_osc_of_setup(struct device_node *node)
+{
+ struct clk_init_data init;
+ struct vexpress_osc *osc;
+ struct clk *clk;
+ u32 range[2];
+
+ osc = kzalloc(sizeof(*osc), GFP_KERNEL);
+ if (!osc)
+ goto error;
+
+ osc->func = vexpress_config_func_get_by_node(node);
+ if (!osc->func) {
+ pr_err("Failed to obtain config func for node '%s'!\n",
+ node->name);
+ goto error;
+ }
+
+ if (of_property_read_u32_array(node, "freq-range", range,
+ ARRAY_SIZE(range)) == 0) {
+ osc->rate_min = range[0];
+ osc->rate_max = range[1];
+ }
+
+ of_property_read_string(node, "clock-output-names", &init.name);
+ if (!init.name)
+ init.name = node->name;
+
+ init.ops = &vexpress_osc_ops;
+ init.flags = CLK_IS_ROOT;
+ init.num_parents = 0;
+
+ osc->hw.init = &init;
+
+ clk = clk_register(NULL, &osc->hw);
+ if (IS_ERR(clk)) {
+ pr_err("Failed to register clock '%s'!\n", init.name);
+ goto error;
+ }
+
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+ pr_debug("Registered clock '%s'\n", init.name);
+
+ return;
+
+error:
+ if (osc->func)
+ vexpress_config_func_put(osc->func);
+ kfree(osc);
+}
diff --git a/drivers/clk/versatile/clk-vexpress.c b/drivers/clk/versatile/clk-vexpress.c
new file mode 100644
index 000000000000..c742ac7c60bb
--- /dev/null
+++ b/drivers/clk/versatile/clk-vexpress.c
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2012 ARM Limited
+ */
+
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/vexpress.h>
+
+#include <asm/hardware/sp810.h>
+
+static struct clk *vexpress_sp810_timerclken[4];
+static DEFINE_SPINLOCK(vexpress_sp810_lock);
+
+static void __init vexpress_sp810_init(void __iomem *base)
+{
+ int i;
+
+ if (WARN_ON(!base))
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++) {
+ char name[12];
+ const char *parents[] = {
+ "v2m:refclk32khz", /* REFCLK */
+ "v2m:refclk1mhz" /* TIMCLK */
+ };
+
+ snprintf(name, ARRAY_SIZE(name), "timerclken%d", i);
+
+ vexpress_sp810_timerclken[i] = clk_register_mux(NULL, name,
+ parents, 2, 0, base + SCCTRL,
+ SCCTRL_TIMERENnSEL_SHIFT(i), 1,
+ 0, &vexpress_sp810_lock);
+
+ if (WARN_ON(IS_ERR(vexpress_sp810_timerclken[i])))
+ break;
+ }
+}
+
+
+static const char * const vexpress_clk_24mhz_periphs[] __initconst = {
+ "mb:uart0", "mb:uart1", "mb:uart2", "mb:uart3",
+ "mb:mmci", "mb:kmi0", "mb:kmi1"
+};
+
+void __init vexpress_clk_init(void __iomem *sp810_base)
+{
+ struct clk *clk;
+ int i;
+
+ clk = clk_register_fixed_rate(NULL, "dummy_apb_pclk", NULL,
+ CLK_IS_ROOT, 0);
+ WARN_ON(clk_register_clkdev(clk, "apb_pclk", NULL));
+
+ clk = clk_register_fixed_rate(NULL, "v2m:clk_24mhz", NULL,
+ CLK_IS_ROOT, 24000000);
+ for (i = 0; i < ARRAY_SIZE(vexpress_clk_24mhz_periphs); i++)
+ WARN_ON(clk_register_clkdev(clk, NULL,
+ vexpress_clk_24mhz_periphs[i]));
+
+ clk = clk_register_fixed_rate(NULL, "v2m:refclk32khz", NULL,
+ CLK_IS_ROOT, 32768);
+ WARN_ON(clk_register_clkdev(clk, NULL, "v2m:wdt"));
+
+ clk = clk_register_fixed_rate(NULL, "v2m:refclk1mhz", NULL,
+ CLK_IS_ROOT, 1000000);
+
+ vexpress_sp810_init(sp810_base);
+
+ for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++)
+ WARN_ON(clk_set_parent(vexpress_sp810_timerclken[i], clk));
+
+ WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[0],
+ "v2m-timer0", "sp804"));
+ WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1],
+ "v2m-timer1", "sp804"));
+}
+
+#if defined(CONFIG_OF)
+
+struct clk *vexpress_sp810_of_get(struct of_phandle_args *clkspec, void *data)
+{
+ if (WARN_ON(clkspec->args_count != 1 || clkspec->args[0] >
+ ARRAY_SIZE(vexpress_sp810_timerclken)))
+ return NULL;
+
+ return vexpress_sp810_timerclken[clkspec->args[0]];
+}
+
+static const __initconst struct of_device_id vexpress_fixed_clk_match[] = {
+ { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
+ { .compatible = "arm,vexpress-osc", .data = vexpress_osc_of_setup, },
+ {}
+};
+
+void __init vexpress_clk_of_init(void)
+{
+ struct device_node *node;
+ struct clk *clk;
+ struct clk *refclk, *timclk;
+
+ of_clk_init(vexpress_fixed_clk_match);
+
+ node = of_find_compatible_node(NULL, NULL, "arm,sp810");
+ vexpress_sp810_init(of_iomap(node, 0));
+ of_clk_add_provider(node, vexpress_sp810_of_get, NULL);
+
+ /* Select "better" (faster) parent for SP804 timers */
+ refclk = of_clk_get_by_name(node, "refclk");
+ timclk = of_clk_get_by_name(node, "timclk");
+ if (!WARN_ON(IS_ERR(refclk) || IS_ERR(timclk))) {
+ int i = 0;
+
+ if (clk_get_rate(refclk) > clk_get_rate(timclk))
+ clk = refclk;
+ else
+ clk = timclk;
+
+ for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++)
+ WARN_ON(clk_set_parent(vexpress_sp810_timerclken[i],
+ clk));
+ }
+
+ WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[0],
+ "v2m-timer0", "sp804"));
+ WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1],
+ "v2m-timer1", "sp804"));
+}
+
+#endif
diff --git a/drivers/cpufreq/db8500-cpufreq.c b/drivers/cpufreq/db8500-cpufreq.c
index 74b830b635a6..4f154bc0ebe4 100644
--- a/drivers/cpufreq/db8500-cpufreq.c
+++ b/drivers/cpufreq/db8500-cpufreq.c
@@ -8,43 +8,17 @@
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*
*/
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cpufreq.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
#include <mach/id.h>
-static struct cpufreq_frequency_table freq_table[] = {
- [0] = {
- .index = 0,
- .frequency = 200000,
- },
- [1] = {
- .index = 1,
- .frequency = 400000,
- },
- [2] = {
- .index = 2,
- .frequency = 800000,
- },
- [3] = {
- /* Used for MAX_OPP, if available */
- .index = 3,
- .frequency = CPUFREQ_TABLE_END,
- },
- [4] = {
- .index = 4,
- .frequency = CPUFREQ_TABLE_END,
- },
-};
-
-static enum arm_opp idx2opp[] = {
- ARM_EXTCLK,
- ARM_50_OPP,
- ARM_100_OPP,
- ARM_MAX_OPP
-};
+static struct cpufreq_frequency_table *freq_table;
+static struct clk *armss_clk;
static struct freq_attr *db8500_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
@@ -85,9 +59,9 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy,
for_each_cpu(freqs.cpu, policy->cpus)
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- /* request the PRCM unit for opp change */
- if (prcmu_set_arm_opp(idx2opp[idx])) {
- pr_err("db8500-cpufreq: Failed to set OPP level\n");
+ /* update armss clk frequency */
+ if (clk_set_rate(armss_clk, freq_table[idx].frequency * 1000)) {
+ pr_err("db8500-cpufreq: Failed to update armss clk\n");
return -EINVAL;
}
@@ -100,25 +74,36 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy,
static unsigned int db8500_cpufreq_getspeed(unsigned int cpu)
{
- int i;
- /* request the prcm to get the current ARM opp */
- for (i = 0; prcmu_get_arm_opp() != idx2opp[i]; i++)
- ;
- return freq_table[i].frequency;
+ int i = 0;
+ unsigned long freq = clk_get_rate(armss_clk) / 1000;
+
+ while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
+ if (freq <= freq_table[i].frequency)
+ return freq_table[i].frequency;
+ i++;
+ }
+
+ /* We could not find a corresponding frequency. */
+ pr_err("db8500-cpufreq: Failed to find cpufreq speed\n");
+ return 0;
}
static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
{
- int i, res;
-
- BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
+ int i = 0;
+ int res;
- if (prcmu_has_arm_maxopp())
- freq_table[3].frequency = 1000000;
+ armss_clk = clk_get(NULL, "armss");
+ if (IS_ERR(armss_clk)) {
+ pr_err("db8500-cpufreq : Failed to get armss clk\n");
+ return PTR_ERR(armss_clk);
+ }
pr_info("db8500-cpufreq : Available frequencies:\n");
- for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
+ while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
pr_info(" %d Mhz\n", freq_table[i].frequency/1000);
+ i++;
+ }
/* get policy fields based on the table */
res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
@@ -126,6 +111,7 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
else {
pr_err("db8500-cpufreq : Failed to read policy table\n");
+ clk_put(armss_clk);
return res;
}
@@ -159,12 +145,35 @@ static struct cpufreq_driver db8500_cpufreq_driver = {
.attr = db8500_cpufreq_attr,
};
+static int db8500_cpufreq_probe(struct platform_device *pdev)
+{
+ freq_table = dev_get_platdata(&pdev->dev);
+
+ if (!freq_table) {
+ pr_err("db8500-cpufreq: Failed to fetch cpufreq table\n");
+ return -ENODEV;
+ }
+
+ return cpufreq_register_driver(&db8500_cpufreq_driver);
+}
+
+static struct platform_driver db8500_cpufreq_plat_driver = {
+ .driver = {
+ .name = "cpufreq-u8500",
+ .owner = THIS_MODULE,
+ },
+ .probe = db8500_cpufreq_probe,
+};
+
static int __init db8500_cpufreq_register(void)
{
if (!cpu_is_u8500_family())
return -ENODEV;
pr_info("cpufreq for DB8500 started\n");
- return cpufreq_register_driver(&db8500_cpufreq_driver);
+ return platform_driver_register(&db8500_cpufreq_plat_driver);
}
device_initcall(db8500_cpufreq_register);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("cpufreq driver for DB8500");
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 308c7fb92a60..f6644f59fd9d 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -224,7 +224,7 @@ config CRYPTO_DEV_TALITOS
config CRYPTO_DEV_IXP4XX
tristate "Driver for IXP4xx crypto hardware acceleration"
- depends on ARCH_IXP4XX
+ depends on ARCH_IXP4XX && IXP4XX_QMGR && IXP4XX_NPE
select CRYPTO_DES
select CRYPTO_ALGAPI
select CRYPTO_AUTHENC
diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c
index 8f3f74ce8c7f..21180d6cad6e 100644
--- a/drivers/crypto/ixp4xx_crypto.c
+++ b/drivers/crypto/ixp4xx_crypto.c
@@ -750,12 +750,12 @@ static int setup_cipher(struct crypto_tfm *tfm, int encrypt,
}
if (cipher_cfg & MOD_AES) {
switch (key_len) {
- case 16: keylen_cfg = MOD_AES128 | KEYLEN_128; break;
- case 24: keylen_cfg = MOD_AES192 | KEYLEN_192; break;
- case 32: keylen_cfg = MOD_AES256 | KEYLEN_256; break;
- default:
- *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
- return -EINVAL;
+ case 16: keylen_cfg = MOD_AES128; break;
+ case 24: keylen_cfg = MOD_AES192; break;
+ case 32: keylen_cfg = MOD_AES256; break;
+ default:
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
}
cipher_cfg |= keylen_cfg;
} else if (cipher_cfg & MOD_3DES) {
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 39c75246c2ae..281f566a5513 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -416,10 +416,18 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
dimm->cschannel = chn;
/* Increment csrow location */
- row++;
- if (row == tot_csrows) {
- row = 0;
+ if (layers[0].is_virt_csrow) {
chn++;
+ if (chn == tot_channels) {
+ chn = 0;
+ row++;
+ }
+ } else {
+ row++;
+ if (row == tot_csrows) {
+ row = 0;
+ chn++;
+ }
}
/* Increment dimm location */
diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c
index a09d0667f72a..9d669cd43618 100644
--- a/drivers/edac/i7300_edac.c
+++ b/drivers/edac/i7300_edac.c
@@ -197,8 +197,8 @@ static const char *ferr_fat_fbd_name[] = {
[0] = "Memory Write error on non-redundant retry or "
"FBD configuration Write error on retry",
};
-#define GET_FBD_FAT_IDX(fbderr) (fbderr & (3 << 28))
-#define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
+#define GET_FBD_FAT_IDX(fbderr) (((fbderr) >> 28) & 3)
+#define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 22))
#define FERR_NF_FBD 0xa0
static const char *ferr_nf_fbd_name[] = {
@@ -225,7 +225,7 @@ static const char *ferr_nf_fbd_name[] = {
[1] = "Aliased Uncorrectable Non-Mirrored Demand Data ECC",
[0] = "Uncorrectable Data ECC on Replay",
};
-#define GET_FBD_NF_IDX(fbderr) (fbderr & (3 << 28))
+#define GET_FBD_NF_IDX(fbderr) (((fbderr) >> 28) & 3)
#define FERR_NF_FBD_ERR_MASK ((1 << 24) | (1 << 23) | (1 << 22) | (1 << 21) |\
(1 << 18) | (1 << 17) | (1 << 16) | (1 << 15) |\
(1 << 14) | (1 << 13) | (1 << 11) | (1 << 10) |\
@@ -464,7 +464,7 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
errnum = find_first_bit(&errors,
ARRAY_SIZE(ferr_nf_fbd_name));
specific = GET_ERR_FROM_TABLE(ferr_nf_fbd_name, errnum);
- branch = (GET_FBD_FAT_IDX(error_reg) == 2) ? 1 : 0;
+ branch = (GET_FBD_NF_IDX(error_reg) == 2) ? 1 : 0;
pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
REDMEMA, &syndrome);
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index 3672101023bd..10c8c00d6469 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -816,7 +816,7 @@ static ssize_t i7core_inject_store_##param( \
struct device_attribute *mattr, \
const char *data, size_t count) \
{ \
- struct mem_ctl_info *mci = to_mci(dev); \
+ struct mem_ctl_info *mci = dev_get_drvdata(dev); \
struct i7core_pvt *pvt; \
long value; \
int rc; \
@@ -845,7 +845,7 @@ static ssize_t i7core_inject_show_##param( \
struct device_attribute *mattr, \
char *data) \
{ \
- struct mem_ctl_info *mci = to_mci(dev); \
+ struct mem_ctl_info *mci = dev_get_drvdata(dev); \
struct i7core_pvt *pvt; \
\
pvt = mci->pvt_info; \
@@ -1052,7 +1052,7 @@ static ssize_t i7core_show_counter_##param( \
struct device_attribute *mattr, \
char *data) \
{ \
- struct mem_ctl_info *mci = to_mci(dev); \
+ struct mem_ctl_info *mci = dev_get_drvdata(dev); \
struct i7core_pvt *pvt = mci->pvt_info; \
\
edac_dbg(1, "\n"); \
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
index 069e26c11c4f..a98020409fa9 100644
--- a/drivers/edac/i82975x_edac.c
+++ b/drivers/edac/i82975x_edac.c
@@ -370,10 +370,6 @@ static enum dev_type i82975x_dram_type(void __iomem *mch_window, int rank)
static void i82975x_init_csrows(struct mem_ctl_info *mci,
struct pci_dev *pdev, void __iomem *mch_window)
{
- static const char *labels[4] = {
- "DIMM A1", "DIMM A2",
- "DIMM B1", "DIMM B2"
- };
struct csrow_info *csrow;
unsigned long last_cumul_size;
u8 value;
@@ -423,9 +419,10 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
dimm = mci->csrows[index]->channels[chan]->dimm;
dimm->nr_pages = nr_pages / csrow->nr_channels;
- strncpy(csrow->channels[chan]->dimm->label,
- labels[(index >> 1) + (chan * 2)],
- EDAC_MC_LABEL_LEN);
+
+ snprintf(csrow->channels[chan]->dimm->label, EDAC_MC_LABEL_LEN, "DIMM %c%d",
+ (chan == 0) ? 'A' : 'B',
+ index);
dimm->grain = 1 << 7; /* 128Byte cache-line resolution */
dimm->dtype = i82975x_dram_type(mch_window, index);
dimm->mtype = MEM_DDR2; /* I82975x supports only DDR2 */
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index f1a45997aea8..d542a141811a 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -19,6 +19,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
+#include <linux/pinctrl/pinctrl.h>
#include <linux/slab.h>
/* Private data structure for of_gpiochip_find_and_xlate */
@@ -216,6 +217,54 @@ err0:
}
EXPORT_SYMBOL(of_mm_gpiochip_add);
+#ifdef CONFIG_PINCTRL
+static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
+{
+ struct device_node *np = chip->of_node;
+ struct of_phandle_args pinspec;
+ struct pinctrl_dev *pctldev;
+ int index = 0, ret;
+
+ if (!np)
+ return;
+
+ do {
+ ret = of_parse_phandle_with_args(np, "gpio-ranges",
+ "#gpio-range-cells", index, &pinspec);
+ if (ret)
+ break;
+
+ pctldev = of_pinctrl_get(pinspec.np);
+ if (!pctldev)
+ break;
+
+ /*
+ * This assumes that the n GPIO pins are consecutive in the
+ * GPIO number space, and that the pins are also consecutive
+ * in their local number space. Currently it is not possible
+ * to add different ranges for one and the same GPIO chip,
+ * as the code assumes that we have one consecutive range
+ * on both, mapping 1-to-1.
+ *
+ * TODO: make the OF bindings handle multiple sparse ranges
+ * on the same GPIO chip.
+ */
+ ret = gpiochip_add_pin_range(chip,
+ pinctrl_dev_get_name(pctldev),
+ 0, /* offset in gpiochip */
+ pinspec.args[0],
+ pinspec.args[1]);
+
+ if (ret)
+ break;
+
+ } while (index++);
+}
+
+#else
+static void of_gpiochip_add_pin_range(struct gpio_chip *chip) {}
+#endif
+
void of_gpiochip_add(struct gpio_chip *chip)
{
if ((!chip->of_node) && (chip->dev))
@@ -229,11 +278,14 @@ void of_gpiochip_add(struct gpio_chip *chip)
chip->of_xlate = of_gpio_simple_xlate;
}
+ of_gpiochip_add_pin_range(chip);
of_node_get(chip->of_node);
}
void of_gpiochip_remove(struct gpio_chip *chip)
{
+ gpiochip_remove_pin_ranges(chip);
+
if (chip->of_node)
of_node_put(chip->of_node);
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 1c8d9e3380e1..58b9838801c0 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1083,6 +1083,10 @@ int gpiochip_add(struct gpio_chip *chip)
}
}
+#ifdef CONFIG_PINCTRL
+ INIT_LIST_HEAD(&chip->pin_ranges);
+#endif
+
of_gpiochip_add(chip);
unlock:
@@ -1123,6 +1127,7 @@ int gpiochip_remove(struct gpio_chip *chip)
spin_lock_irqsave(&gpio_lock, flags);
+ gpiochip_remove_pin_ranges(chip);
of_gpiochip_remove(chip);
for (id = chip->base; id < chip->base + chip->ngpio; id++) {
@@ -1180,6 +1185,77 @@ struct gpio_chip *gpiochip_find(void *data,
}
EXPORT_SYMBOL_GPL(gpiochip_find);
+#ifdef CONFIG_PINCTRL
+
+/**
+ * gpiochip_add_pin_range() - add a range for GPIO <-> pin mapping
+ * @chip: the gpiochip to add the range for
+ * @pinctrl_name: the dev_name() of the pin controller to map to
+ * @gpio_offset: the start offset in the current gpio_chip number space
+ * @pin_offset: the start offset in the pin controller number space
+ * @npins: the number of pins from the offset of each pin space (GPIO and
+ * pin controller) to accumulate in this range
+ */
+int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
+ unsigned int gpio_offset, unsigned int pin_offset,
+ unsigned int npins)
+{
+ struct gpio_pin_range *pin_range;
+ int ret;
+
+ pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL);
+ if (!pin_range) {
+ pr_err("%s: GPIO chip: failed to allocate pin ranges\n",
+ chip->label);
+ return -ENOMEM;
+ }
+
+ /* Use local offset as range ID */
+ pin_range->range.id = gpio_offset;
+ pin_range->range.gc = chip;
+ pin_range->range.name = chip->label;
+ pin_range->range.base = chip->base + gpio_offset;
+ pin_range->range.pin_base = pin_offset;
+ pin_range->range.npins = npins;
+ pin_range->pctldev = pinctrl_find_and_add_gpio_range(pinctl_name,
+ &pin_range->range);
+ if (IS_ERR(pin_range->pctldev)) {
+ ret = PTR_ERR(pin_range->pctldev);
+ pr_err("%s: GPIO chip: could not create pin range\n",
+ chip->label);
+ kfree(pin_range);
+ return ret;
+ }
+ pr_debug("GPIO chip %s: created GPIO range %d->%d ==> %s PIN %d->%d\n",
+ chip->label, gpio_offset, gpio_offset + npins - 1,
+ pinctl_name,
+ pin_offset, pin_offset + npins - 1);
+
+ list_add_tail(&pin_range->node, &chip->pin_ranges);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gpiochip_add_pin_range);
+
+/**
+ * gpiochip_remove_pin_ranges() - remove all the GPIO <-> pin mappings
+ * @chip: the chip to remove all the mappings for
+ */
+void gpiochip_remove_pin_ranges(struct gpio_chip *chip)
+{
+ struct gpio_pin_range *pin_range, *tmp;
+
+ list_for_each_entry_safe(pin_range, tmp, &chip->pin_ranges, node) {
+ list_del(&pin_range->node);
+ pinctrl_remove_gpio_range(pin_range->pctldev,
+ &pin_range->range);
+ kfree(pin_range);
+ }
+}
+EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
+
+#endif /* CONFIG_PINCTRL */
+
/* These "optional" allocation calls help prevent drivers from stomping
* on each other, and help provide better diagnostics in debugfs.
* They're called even less than the "set direction" calls.
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 241ad1eeec64..f2df06c603f7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -226,6 +226,12 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
* already updated or not by exynos_drm_encoder_dpms function.
*/
exynos_encoder->updated = true;
+
+ /*
+ * In case of setcrtc, there is no way to update encoder's dpms
+ * so update it here.
+ */
+ exynos_encoder->dpms = DRM_MODE_DPMS_ON;
}
static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
@@ -507,6 +513,6 @@ void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
* because the setting for disabling the overlay will be updated
* at vsync.
*/
- if (overlay_ops->wait_for_vblank)
+ if (overlay_ops && overlay_ops->wait_for_vblank)
overlay_ops->wait_for_vblank(manager->dev);
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 67eb6ba56edf..e7466c4414cb 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -87,7 +87,8 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
dev->mode_config.fb_base = (resource_size_t)buffer->dma_addr;
fbi->screen_base = buffer->kvaddr + offset;
- fbi->fix.smem_start = (unsigned long)(buffer->dma_addr + offset);
+ fbi->fix.smem_start = (unsigned long)(page_to_phys(buffer->pages[0]) +
+ offset);
fbi->screen_size = size;
fbi->fix.smem_len = size;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 130a2b510d4a..e08478f19f1a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -61,11 +61,11 @@ struct fimd_driver_data {
unsigned int timing_base;
};
-struct fimd_driver_data exynos4_fimd_driver_data = {
+static struct fimd_driver_data exynos4_fimd_driver_data = {
.timing_base = 0x0,
};
-struct fimd_driver_data exynos5_fimd_driver_data = {
+static struct fimd_driver_data exynos5_fimd_driver_data = {
.timing_base = 0x20000,
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index 60b877a388c2..862ca1eb2102 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -204,7 +204,6 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
return ret;
plane->crtc = crtc;
- plane->fb = crtc->fb;
exynos_plane_commit(plane);
exynos_plane_dpms(plane, DRM_MODE_DPMS_ON);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 107f09befe92..9b285da4449b 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1796,7 +1796,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
*/
mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
gfp = mapping_gfp_mask(mapping);
- gfp |= __GFP_NORETRY | __GFP_NOWARN;
+ gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD;
gfp &= ~(__GFP_IO | __GFP_WAIT);
for_each_sg(st->sgl, sg, page_count, i) {
page = shmem_read_mapping_page_gfp(mapping, i, gfp);
@@ -1809,7 +1809,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
* our own buffer, now let the real VM do its job and
* go down in flames if truly OOM.
*/
- gfp &= ~(__GFP_NORETRY | __GFP_NOWARN);
+ gfp &= ~(__GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD);
gfp |= __GFP_IO | __GFP_WAIT;
i915_gem_shrink_all(dev_priv);
@@ -1817,7 +1817,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
if (IS_ERR(page))
goto err_pages;
- gfp |= __GFP_NORETRY | __GFP_NOWARN;
+ gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD;
gfp &= ~(__GFP_IO | __GFP_WAIT);
}
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 0ed6baff4b0c..56846ed5ee55 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -499,12 +499,8 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
edp = find_section(bdb, BDB_EDP);
if (!edp) {
- if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) {
- DRM_DEBUG_KMS("No eDP BDB found but eDP panel "
- "supported, assume %dbpp panel color "
- "depth.\n",
- dev_priv->edp.bpp);
- }
+ if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support)
+ DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported.\n");
return;
}
@@ -657,9 +653,6 @@ init_vbt_defaults(struct drm_i915_private *dev_priv)
dev_priv->lvds_use_ssc = 1;
dev_priv->lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1);
DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->lvds_ssc_freq);
-
- /* eDP data */
- dev_priv->edp.bpp = 18;
}
static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 4154bcd7a070..b426d44a2b05 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3845,7 +3845,7 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
/* Use VBT settings if we have an eDP panel */
unsigned int edp_bpc = dev_priv->edp.bpp / 3;
- if (edp_bpc < display_bpc) {
+ if (edp_bpc && edp_bpc < display_bpc) {
DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc);
display_bpc = edp_bpc;
}
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 72f41aaa71ff..442968f8b201 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2373,15 +2373,9 @@ int intel_enable_rc6(const struct drm_device *dev)
if (i915_enable_rc6 >= 0)
return i915_enable_rc6;
- if (INTEL_INFO(dev)->gen == 5) {
-#ifdef CONFIG_INTEL_IOMMU
- /* Disable rc6 on ilk if VT-d is on. */
- if (intel_iommu_gfx_mapped)
- return false;
-#endif
- DRM_DEBUG_DRIVER("Ironlake: only RC6 available\n");
- return INTEL_RC6_ENABLE;
- }
+ /* Disable RC6 on Ironlake */
+ if (INTEL_INFO(dev)->gen == 5)
+ return 0;
if (IS_HASWELL(dev)) {
DRM_DEBUG_DRIVER("Haswell: only RC6 available\n");
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index c600fb06e25e..a6ac0b416964 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -2201,7 +2201,6 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
intel_sdvo->is_hdmi = true;
}
- intel_sdvo->base.cloneable = true;
intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
if (intel_sdvo->is_hdmi)
@@ -2232,7 +2231,6 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)
intel_sdvo->is_tv = true;
intel_sdvo->base.needs_tv_clock = true;
- intel_sdvo->base.cloneable = false;
intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
@@ -2275,8 +2273,6 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)
intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
}
- intel_sdvo->base.cloneable = true;
-
intel_sdvo_connector_init(intel_sdvo_connector,
intel_sdvo);
return true;
@@ -2307,9 +2303,6 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
}
- /* SDVO LVDS is not cloneable because the input mode gets adjusted by the encoder */
- intel_sdvo->base.cloneable = false;
-
intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
goto err;
@@ -2721,6 +2714,16 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
goto err_output;
}
+ /*
+ * Cloning SDVO with anything is often impossible, since the SDVO
+ * encoder can request a special input timing mode. And even if that's
+ * not the case we have evidence that cloning a plain unscaled mode with
+ * VGA doesn't really work. Furthermore the cloning flags are way too
+ * simplistic anyway to express such constraints, so just give up on
+ * cloning for SDVO encoders.
+ */
+ intel_sdvo->base.cloneable = false;
+
/* Only enable the hotplug irq if we need it, to work around noisy
* hotplug lines.
*/
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 3bce0299f64a..24d932f53203 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -1696,42 +1696,22 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
return ATOM_PPLL2;
DRM_ERROR("unable to allocate a PPLL\n");
return ATOM_PPLL_INVALID;
- } else if (ASIC_IS_AVIVO(rdev)) {
- /* in DP mode, the DP ref clock can come from either PPLL
- * depending on the asic:
- * DCE3: PPLL1 or PPLL2
- */
- if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) {
- /* use the same PPLL for all DP monitors */
- pll = radeon_get_shared_dp_ppll(crtc);
- if (pll != ATOM_PPLL_INVALID)
- return pll;
- } else {
- /* use the same PPLL for all monitors with the same clock */
- pll = radeon_get_shared_nondp_ppll(crtc);
- if (pll != ATOM_PPLL_INVALID)
- return pll;
- }
- /* all other cases */
- pll_in_use = radeon_get_pll_use_mask(crtc);
- /* the order shouldn't matter here, but we probably
- * need this until we have atomic modeset
- */
- if (rdev->flags & RADEON_IS_IGP) {
- if (!(pll_in_use & (1 << ATOM_PPLL1)))
- return ATOM_PPLL1;
- if (!(pll_in_use & (1 << ATOM_PPLL2)))
- return ATOM_PPLL2;
- } else {
- if (!(pll_in_use & (1 << ATOM_PPLL2)))
- return ATOM_PPLL2;
- if (!(pll_in_use & (1 << ATOM_PPLL1)))
- return ATOM_PPLL1;
- }
- DRM_ERROR("unable to allocate a PPLL\n");
- return ATOM_PPLL_INVALID;
} else {
/* on pre-R5xx asics, the crtc to pll mapping is hardcoded */
+ /* some atombios (observed in some DCE2/DCE3) code have a bug,
+ * the matching btw pll and crtc is done through
+ * PCLK_CRTC[1|2]_CNTL (0x480/0x484) but atombios code use the
+ * pll (1 or 2) to select which register to write. ie if using
+ * pll1 it will use PCLK_CRTC1_CNTL (0x480) and if using pll2
+ * it will use PCLK_CRTC2_CNTL (0x484), it then use crtc id to
+ * choose which value to write. Which is reverse order from
+ * register logic. So only case that works is when pllid is
+ * same as crtcid or when both pll and crtc are enabled and
+ * both use same clock.
+ *
+ * So just return crtc id as if crtc and pll were hard linked
+ * together even if they aren't
+ */
return radeon_crtc->crtc_id;
}
}
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index c4633de64465..4800d4c2a7b7 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -334,6 +334,16 @@ config SENSORS_DA9052_ADC
This driver can also be built as module. If so, the module
will be called da9052-hwmon.
+config SENSORS_DA9055
+ tristate "Dialog Semiconductor DA9055 ADC"
+ depends on MFD_DA9055
+ help
+ If you say yes here you get support for ADC on the Dialog
+ Semiconductor DA9055 PMIC.
+
+ This driver can also be built as a module. If so, the module
+ will be called da9055-hwmon.
+
config SENSORS_I5K_AMB
tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
depends on PCI
@@ -455,7 +465,7 @@ config SENSORS_HIH6130
config SENSORS_CORETEMP
tristate "Intel Core/Core2/Atom temperature sensor"
- depends on X86 && PCI
+ depends on X86
help
If you say yes here you get support for the temperature
sensor inside your CPU. Most of the family 6 CPUs
@@ -1106,11 +1116,12 @@ config SENSORS_ADS1015
will be called ads1015.
config SENSORS_ADS7828
- tristate "Texas Instruments ADS7828"
+ tristate "Texas Instruments ADS7828 and compatibles"
depends on I2C
help
- If you say yes here you get support for Texas Instruments ADS7828
- 12-bit 8-channel ADC device.
+ If you say yes here you get support for Texas Instruments ADS7828 and
+ ADS7830 8-channel A/D converters. ADS7828 resolution is 12-bit, while
+ it is 8-bit on ADS7830.
This driver can also be built as a module. If so, the module
will be called ads7828.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 8d5fcb5e8e9f..a930f0997d25 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
+obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o
obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
obj-$(CONFIG_SENSORS_DS620) += ds620.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index 1f9e8af0f322..409b5c16defb 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -1,12 +1,14 @@
/*
- * ads7828.c - lm_sensors driver for ads7828 12-bit 8-channel ADC
+ * ads7828.c - driver for TI ADS7828 8-channel A/D converter and compatibles
* (C) 2007 EADS Astrium
*
* This driver is based on the lm75 and other lm_sensors/hwmon drivers
*
* Written by Steve Hardy <shardy@redhat.com>
*
- * Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads7828.pdf
+ * ADS7830 support, by Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
+ *
+ * For further information, see the Documentation/hwmon/ads7828 file.
*
* 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
@@ -23,63 +25,48 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
-#include <linux/i2c.h>
+#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
-#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/platform_data/ads7828.h>
+#include <linux/slab.h>
/* The ADS7828 registers */
-#define ADS7828_NCH 8 /* 8 channels of 12-bit A-D supported */
-#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */
-#define ADS7828_CMD_SD_DIFF 0x00 /* Differential inputs */
-#define ADS7828_CMD_PD0 0x0 /* Power Down between A-D conversions */
-#define ADS7828_CMD_PD1 0x04 /* Internal ref OFF && A-D ON */
-#define ADS7828_CMD_PD2 0x08 /* Internal ref ON && A-D OFF */
-#define ADS7828_CMD_PD3 0x0C /* Internal ref ON && A-D ON */
-#define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */
-
-/* Addresses to scan */
-static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
- I2C_CLIENT_END };
-
-/* Module parameters */
-static bool se_input = 1; /* Default is SE, 0 == diff */
-static bool int_vref = 1; /* Default is internal ref ON */
-static int vref_mv = ADS7828_INT_VREF_MV; /* set if vref != 2.5V */
-module_param(se_input, bool, S_IRUGO);
-module_param(int_vref, bool, S_IRUGO);
-module_param(vref_mv, int, S_IRUGO);
-
-/* Global Variables */
-static u8 ads7828_cmd_byte; /* cmd byte without channel bits */
-static unsigned int ads7828_lsb_resol; /* resolution of the ADC sample lsb */
-
-/* Each client has this additional data */
+#define ADS7828_NCH 8 /* 8 channels supported */
+#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */
+#define ADS7828_CMD_PD1 0x04 /* Internal vref OFF && A/D ON */
+#define ADS7828_CMD_PD3 0x0C /* Internal vref ON && A/D ON */
+#define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */
+#define ADS7828_EXT_VREF_MV_MIN 50 /* External vref min value 0.05V */
+#define ADS7828_EXT_VREF_MV_MAX 5250 /* External vref max value 5.25V */
+
+/* List of supported devices */
+enum ads7828_chips { ads7828, ads7830 };
+
+/* Client specific data */
struct ads7828_data {
struct device *hwmon_dev;
- struct mutex update_lock; /* mutex protect updates */
- char valid; /* !=0 if following fields are valid */
- unsigned long last_updated; /* In jiffies */
- u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH 12-bit samples */
+ struct mutex update_lock; /* Mutex protecting updates */
+ unsigned long last_updated; /* Last updated time (in jiffies) */
+ u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH samples */
+ bool valid; /* Validity flag */
+ bool diff_input; /* Differential input */
+ bool ext_vref; /* External voltage reference */
+ unsigned int vref_mv; /* voltage reference value */
+ u8 cmd_byte; /* Command byte without channel bits */
+ unsigned int lsb_resol; /* Resolution of the ADC sample LSB */
+ s32 (*read_channel)(const struct i2c_client *client, u8 command);
};
-/* Function declaration - necessary due to function dependencies */
-static int ads7828_detect(struct i2c_client *client,
- struct i2c_board_info *info);
-static int ads7828_probe(struct i2c_client *client,
- const struct i2c_device_id *id);
-
-static inline u8 channel_cmd_byte(int ch)
+/* Command byte C2,C1,C0 - see datasheet */
+static inline u8 ads7828_cmd_byte(u8 cmd, int ch)
{
- /* cmd byte C2,C1,C0 - see datasheet */
- u8 cmd = (((ch>>1) | (ch&0x01)<<2)<<4);
- cmd |= ads7828_cmd_byte;
- return cmd;
+ return cmd | (((ch >> 1) | (ch & 0x01) << 2) << 4);
}
/* Update data for the device (all 8 channels) */
@@ -96,12 +83,11 @@ static struct ads7828_data *ads7828_update_device(struct device *dev)
dev_dbg(&client->dev, "Starting ads7828 update\n");
for (ch = 0; ch < ADS7828_NCH; ch++) {
- u8 cmd = channel_cmd_byte(ch);
- data->adc_input[ch] =
- i2c_smbus_read_word_swapped(client, cmd);
+ u8 cmd = ads7828_cmd_byte(data->cmd_byte, ch);
+ data->adc_input[ch] = data->read_channel(client, cmd);
}
data->last_updated = jiffies;
- data->valid = 1;
+ data->valid = true;
}
mutex_unlock(&data->update_lock);
@@ -110,28 +96,25 @@ static struct ads7828_data *ads7828_update_device(struct device *dev)
}
/* sysfs callback function */
-static ssize_t show_in(struct device *dev, struct device_attribute *da,
- char *buf)
+static ssize_t ads7828_show_in(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ads7828_data *data = ads7828_update_device(dev);
- /* Print value (in mV as specified in sysfs-interface documentation) */
- return sprintf(buf, "%d\n", (data->adc_input[attr->index] *
- ads7828_lsb_resol)/1000);
-}
+ unsigned int value = DIV_ROUND_CLOSEST(data->adc_input[attr->index] *
+ data->lsb_resol, 1000);
-#define in_reg(offset)\
-static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in,\
- NULL, offset)
+ return sprintf(buf, "%d\n", value);
+}
-in_reg(0);
-in_reg(1);
-in_reg(2);
-in_reg(3);
-in_reg(4);
-in_reg(5);
-in_reg(6);
-in_reg(7);
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ads7828_show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ads7828_show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ads7828_show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ads7828_show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ads7828_show_in, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ads7828_show_in, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ads7828_show_in, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ads7828_show_in, NULL, 7);
static struct attribute *ads7828_attributes[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
@@ -152,60 +135,9 @@ static const struct attribute_group ads7828_group = {
static int ads7828_remove(struct i2c_client *client)
{
struct ads7828_data *data = i2c_get_clientdata(client);
+
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
- return 0;
-}
-
-static const struct i2c_device_id ads7828_id[] = {
- { "ads7828", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, ads7828_id);
-
-/* This is the driver that will be inserted */
-static struct i2c_driver ads7828_driver = {
- .class = I2C_CLASS_HWMON,
- .driver = {
- .name = "ads7828",
- },
- .probe = ads7828_probe,
- .remove = ads7828_remove,
- .id_table = ads7828_id,
- .detect = ads7828_detect,
- .address_list = normal_i2c,
-};
-
-/* Return 0 if detection is successful, -ENODEV otherwise */
-static int ads7828_detect(struct i2c_client *client,
- struct i2c_board_info *info)
-{
- struct i2c_adapter *adapter = client->adapter;
- int ch;
-
- /* Check we have a valid client */
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA))
- return -ENODEV;
-
- /*
- * Now, we do the remaining detection. There is no identification
- * dedicated register so attempt to sanity check using knowledge of
- * the chip
- * - Read from the 8 channel addresses
- * - Check the top 4 bits of each result are not set (12 data bits)
- */
- for (ch = 0; ch < ADS7828_NCH; ch++) {
- u16 in_data;
- u8 cmd = channel_cmd_byte(ch);
- in_data = i2c_smbus_read_word_swapped(client, cmd);
- if (in_data & 0xF000) {
- pr_debug("%s : Doesn't look like an ads7828 device\n",
- __func__);
- return -ENODEV;
- }
- }
-
- strlcpy(info->type, "ads7828", I2C_NAME_SIZE);
return 0;
}
@@ -213,6 +145,7 @@ static int ads7828_detect(struct i2c_client *client,
static int ads7828_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct ads7828_platform_data *pdata = client->dev.platform_data;
struct ads7828_data *data;
int err;
@@ -221,10 +154,37 @@ static int ads7828_probe(struct i2c_client *client,
if (!data)
return -ENOMEM;
+ if (pdata) {
+ data->diff_input = pdata->diff_input;
+ data->ext_vref = pdata->ext_vref;
+ if (data->ext_vref)
+ data->vref_mv = pdata->vref_mv;
+ }
+
+ /* Bound Vref with min/max values if it was provided */
+ if (data->vref_mv)
+ data->vref_mv = SENSORS_LIMIT(data->vref_mv,
+ ADS7828_EXT_VREF_MV_MIN,
+ ADS7828_EXT_VREF_MV_MAX);
+ else
+ data->vref_mv = ADS7828_INT_VREF_MV;
+
+ /* ADS7828 uses 12-bit samples, while ADS7830 is 8-bit */
+ if (id->driver_data == ads7828) {
+ data->lsb_resol = DIV_ROUND_CLOSEST(data->vref_mv * 1000, 4096);
+ data->read_channel = i2c_smbus_read_word_swapped;
+ } else {
+ data->lsb_resol = DIV_ROUND_CLOSEST(data->vref_mv * 1000, 256);
+ data->read_channel = i2c_smbus_read_byte_data;
+ }
+
+ data->cmd_byte = data->ext_vref ? ADS7828_CMD_PD1 : ADS7828_CMD_PD3;
+ if (!data->diff_input)
+ data->cmd_byte |= ADS7828_CMD_SD_SE;
+
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
- /* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &ads7828_group);
if (err)
return err;
@@ -232,38 +192,35 @@ static int ads7828_probe(struct i2c_client *client,
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
- goto exit_remove;
+ goto error;
}
return 0;
-exit_remove:
+error:
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
return err;
}
-static int __init sensors_ads7828_init(void)
-{
- /* Initialize the command byte according to module parameters */
- ads7828_cmd_byte = se_input ?
- ADS7828_CMD_SD_SE : ADS7828_CMD_SD_DIFF;
- ads7828_cmd_byte |= int_vref ?
- ADS7828_CMD_PD3 : ADS7828_CMD_PD1;
+static const struct i2c_device_id ads7828_device_ids[] = {
+ { "ads7828", ads7828 },
+ { "ads7830", ads7830 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ads7828_device_ids);
- /* Calculate the LSB resolution */
- ads7828_lsb_resol = (vref_mv*1000)/4096;
+static struct i2c_driver ads7828_driver = {
+ .driver = {
+ .name = "ads7828",
+ },
- return i2c_add_driver(&ads7828_driver);
-}
+ .id_table = ads7828_device_ids,
+ .probe = ads7828_probe,
+ .remove = ads7828_remove,
+};
-static void __exit sensors_ads7828_exit(void)
-{
- i2c_del_driver(&ads7828_driver);
-}
+module_i2c_driver(ads7828_driver);
-MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>");
-MODULE_DESCRIPTION("ADS7828 driver");
MODULE_LICENSE("GPL");
-
-module_init(sensors_ads7828_init);
-module_exit(sensors_ads7828_exit);
+MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>");
+MODULE_DESCRIPTION("Driver for TI ADS7828 A/D converter and compatibles");
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 47b8d84b489d..24426a785ad5 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -34,7 +34,6 @@
#include <linux/list.h>
#include <linux/platform_device.h>
#include <linux/cpu.h>
-#include <linux/pci.h>
#include <linux/smp.h>
#include <linux/moduleparam.h>
#include <asm/msr.h>
@@ -197,14 +196,6 @@ struct tjmax {
};
static const struct tjmax __cpuinitconst tjmax_table[] = {
- { "CPU D410", 100000 },
- { "CPU D425", 100000 },
- { "CPU D510", 100000 },
- { "CPU D525", 100000 },
- { "CPU N450", 100000 },
- { "CPU N455", 100000 },
- { "CPU N470", 100000 },
- { "CPU N475", 100000 },
{ "CPU 230", 100000 }, /* Model 0x1c, stepping 2 */
{ "CPU 330", 125000 }, /* Model 0x1c, stepping 2 */
{ "CPU CE4110", 110000 }, /* Model 0x1c, stepping 10 */
@@ -212,6 +203,28 @@ static const struct tjmax __cpuinitconst tjmax_table[] = {
{ "CPU CE4170", 110000 }, /* Model 0x1c, stepping 10 */
};
+struct tjmax_model {
+ u8 model;
+ u8 mask;
+ int tjmax;
+};
+
+#define ANY 0xff
+
+static const struct tjmax_model __cpuinitconst tjmax_model_table[] = {
+ { 0x1c, 10, 100000 }, /* D4xx, N4xx, D5xx, N5xx */
+ { 0x1c, ANY, 90000 }, /* Z5xx, N2xx, possibly others
+ * Note: Also matches 230 and 330,
+ * which are covered by tjmax_table
+ */
+ { 0x26, ANY, 90000 }, /* Atom Tunnel Creek (Exx), Lincroft (Z6xx)
+ * Note: TjMax for E6xxT is 110C, but CPU type
+ * is undetectable by software
+ */
+ { 0x27, ANY, 90000 }, /* Atom Medfield (Z2460) */
+ { 0x36, ANY, 100000 }, /* Atom Cedar Trail/Cedarview (N2xxx, D2xxx) */
+};
+
static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id,
struct device *dev)
{
@@ -222,7 +235,6 @@ static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id,
int usemsr_ee = 1;
int err;
u32 eax, edx;
- struct pci_dev *host_bridge;
int i;
/* explicit tjmax table entries override heuristics */
@@ -231,32 +243,18 @@ static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id,
return tjmax_table[i].tjmax;
}
+ for (i = 0; i < ARRAY_SIZE(tjmax_model_table); i++) {
+ const struct tjmax_model *tm = &tjmax_model_table[i];
+ if (c->x86_model == tm->model &&
+ (tm->mask == ANY || c->x86_mask == tm->mask))
+ return tm->tjmax;
+ }
+
/* Early chips have no MSR for TjMax */
if (c->x86_model == 0xf && c->x86_mask < 4)
usemsr_ee = 0;
- /* Atom CPUs */
-
- if (c->x86_model == 0x1c || c->x86_model == 0x26
- || c->x86_model == 0x27) {
- usemsr_ee = 0;
-
- host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0));
-
- if (host_bridge && host_bridge->vendor == PCI_VENDOR_ID_INTEL
- && (host_bridge->device == 0xa000 /* NM10 based nettop */
- || host_bridge->device == 0xa010)) /* NM10 based netbook */
- tjmax = 100000;
- else
- tjmax = 90000;
-
- pci_dev_put(host_bridge);
- } else if (c->x86_model == 0x36) {
- usemsr_ee = 0;
- tjmax = 100000;
- }
-
if (c->x86_model > 0xe && usemsr_ee) {
u8 platform_id;
diff --git a/drivers/hwmon/da9052-hwmon.c b/drivers/hwmon/da9052-hwmon.c
index b8d01c5f5713..19704948801c 100644
--- a/drivers/hwmon/da9052-hwmon.c
+++ b/drivers/hwmon/da9052-hwmon.c
@@ -60,30 +60,17 @@ static inline int vbbat_reg_to_mV(int value)
return DIV_ROUND_CLOSEST(value * 2500, 512);
}
-static int da9052_enable_vddout_channel(struct da9052 *da9052)
+static inline int da9052_enable_vddout_channel(struct da9052 *da9052)
{
- int ret;
-
- ret = da9052_reg_read(da9052, DA9052_ADC_CONT_REG);
- if (ret < 0)
- return ret;
-
- ret |= DA9052_ADCCONT_AUTOVDDEN;
-
- return da9052_reg_write(da9052, DA9052_ADC_CONT_REG, ret);
+ return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
+ DA9052_ADCCONT_AUTOVDDEN,
+ DA9052_ADCCONT_AUTOVDDEN);
}
-static int da9052_disable_vddout_channel(struct da9052 *da9052)
+static inline int da9052_disable_vddout_channel(struct da9052 *da9052)
{
- int ret;
-
- ret = da9052_reg_read(da9052, DA9052_ADC_CONT_REG);
- if (ret < 0)
- return ret;
-
- ret &= ~DA9052_ADCCONT_AUTOVDDEN;
-
- return da9052_reg_write(da9052, DA9052_ADC_CONT_REG, ret);
+ return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
+ DA9052_ADCCONT_AUTOVDDEN, 0);
}
static ssize_t da9052_read_vddout(struct device *dev,
diff --git a/drivers/hwmon/da9055-hwmon.c b/drivers/hwmon/da9055-hwmon.c
new file mode 100644
index 000000000000..9465c050c326
--- /dev/null
+++ b/drivers/hwmon/da9055-hwmon.c
@@ -0,0 +1,336 @@
+/*
+ * HWMON Driver for Dialog DA9055
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+
+#include <linux/mfd/da9055/core.h>
+#include <linux/mfd/da9055/reg.h>
+
+#define DA9055_ADCIN_DIV 102
+#define DA9055_VSYS_DIV 85
+
+#define DA9055_ADC_VSYS 0
+#define DA9055_ADC_ADCIN1 1
+#define DA9055_ADC_ADCIN2 2
+#define DA9055_ADC_ADCIN3 3
+#define DA9055_ADC_TJUNC 4
+
+struct da9055_hwmon {
+ struct da9055 *da9055;
+ struct device *class_device;
+ struct mutex hwmon_lock;
+ struct mutex irq_lock;
+ struct completion done;
+};
+
+static const char * const input_names[] = {
+ [DA9055_ADC_VSYS] = "VSYS",
+ [DA9055_ADC_ADCIN1] = "ADC IN1",
+ [DA9055_ADC_ADCIN2] = "ADC IN2",
+ [DA9055_ADC_ADCIN3] = "ADC IN3",
+ [DA9055_ADC_TJUNC] = "CHIP TEMP",
+};
+
+static const u8 chan_mux[DA9055_ADC_TJUNC + 1] = {
+ [DA9055_ADC_VSYS] = DA9055_ADC_MUX_VSYS,
+ [DA9055_ADC_ADCIN1] = DA9055_ADC_MUX_ADCIN1,
+ [DA9055_ADC_ADCIN2] = DA9055_ADC_MUX_ADCIN2,
+ [DA9055_ADC_ADCIN3] = DA9055_ADC_MUX_ADCIN3,
+ [DA9055_ADC_TJUNC] = DA9055_ADC_MUX_T_SENSE,
+};
+
+static int da9055_adc_manual_read(struct da9055_hwmon *hwmon,
+ unsigned char channel)
+{
+ int ret;
+ unsigned short calc_data;
+ unsigned short data;
+ unsigned char mux_sel;
+ struct da9055 *da9055 = hwmon->da9055;
+
+ if (channel > DA9055_ADC_TJUNC)
+ return -EINVAL;
+
+ mutex_lock(&hwmon->irq_lock);
+
+ /* Selects desired MUX for manual conversion */
+ mux_sel = chan_mux[channel] | DA9055_ADC_MAN_CONV;
+
+ ret = da9055_reg_write(da9055, DA9055_REG_ADC_MAN, mux_sel);
+ if (ret < 0)
+ goto err;
+
+ /* Wait for an interrupt */
+ if (!wait_for_completion_timeout(&hwmon->done,
+ msecs_to_jiffies(500))) {
+ dev_err(da9055->dev,
+ "timeout waiting for ADC conversion interrupt\n");
+ ret = -ETIMEDOUT;
+ goto err;
+ }
+
+ ret = da9055_reg_read(da9055, DA9055_REG_ADC_RES_H);
+ if (ret < 0)
+ goto err;
+
+ calc_data = (unsigned short)ret;
+ data = calc_data << 2;
+
+ ret = da9055_reg_read(da9055, DA9055_REG_ADC_RES_L);
+ if (ret < 0)
+ goto err;
+
+ calc_data = (unsigned short)(ret & DA9055_ADC_LSB_MASK);
+ data |= calc_data;
+
+ ret = data;
+
+err:
+ mutex_unlock(&hwmon->irq_lock);
+ return ret;
+}
+
+static irqreturn_t da9055_auxadc_irq(int irq, void *irq_data)
+{
+ struct da9055_hwmon *hwmon = irq_data;
+
+ complete(&hwmon->done);
+
+ return IRQ_HANDLED;
+}
+
+/* Conversion function for VSYS and ADCINx */
+static inline int volt_reg_to_mV(int value, int channel)
+{
+ if (channel == DA9055_ADC_VSYS)
+ return DIV_ROUND_CLOSEST(value * 1000, DA9055_VSYS_DIV) + 2500;
+ else
+ return DIV_ROUND_CLOSEST(value * 1000, DA9055_ADCIN_DIV);
+}
+
+static int da9055_enable_auto_mode(struct da9055 *da9055, int channel)
+{
+
+ return da9055_reg_update(da9055, DA9055_REG_ADC_CONT, 1 << channel,
+ 1 << channel);
+
+}
+
+static int da9055_disable_auto_mode(struct da9055 *da9055, int channel)
+{
+
+ return da9055_reg_update(da9055, DA9055_REG_ADC_CONT, 1 << channel, 0);
+}
+
+static ssize_t da9055_read_auto_ch(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct da9055_hwmon *hwmon = dev_get_drvdata(dev);
+ int ret, adc;
+ int channel = to_sensor_dev_attr(devattr)->index;
+
+ mutex_lock(&hwmon->hwmon_lock);
+
+ ret = da9055_enable_auto_mode(hwmon->da9055, channel);
+ if (ret < 0)
+ goto hwmon_err;
+
+ usleep_range(10000, 10500);
+
+ adc = da9055_reg_read(hwmon->da9055, DA9055_REG_VSYS_RES + channel);
+ if (adc < 0) {
+ ret = adc;
+ goto hwmon_err_release;
+ }
+
+ ret = da9055_disable_auto_mode(hwmon->da9055, channel);
+ if (ret < 0)
+ goto hwmon_err;
+
+ mutex_unlock(&hwmon->hwmon_lock);
+
+ return sprintf(buf, "%d\n", volt_reg_to_mV(adc, channel));
+
+hwmon_err_release:
+ da9055_disable_auto_mode(hwmon->da9055, channel);
+hwmon_err:
+ mutex_unlock(&hwmon->hwmon_lock);
+ return ret;
+}
+
+static ssize_t da9055_read_tjunc(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct da9055_hwmon *hwmon = dev_get_drvdata(dev);
+ int tjunc;
+ int toffset;
+
+ tjunc = da9055_adc_manual_read(hwmon, DA9055_ADC_TJUNC);
+ if (tjunc < 0)
+ return tjunc;
+
+ toffset = da9055_reg_read(hwmon->da9055, DA9055_REG_T_OFFSET);
+ if (toffset < 0)
+ return toffset;
+
+ /*
+ * Degrees celsius = -0.4084 * (ADC_RES - T_OFFSET) + 307.6332
+ * T_OFFSET is a trim value used to improve accuracy of the result
+ */
+ return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(-4084 * (tjunc - toffset)
+ + 3076332, 10000));
+}
+
+static ssize_t da9055_hwmon_show_name(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ return sprintf(buf, "da9055-hwmon\n");
+}
+
+static ssize_t show_label(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ return sprintf(buf, "%s\n",
+ input_names[to_sensor_dev_attr(devattr)->index]);
+}
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, da9055_read_auto_ch, NULL,
+ DA9055_ADC_VSYS);
+static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL,
+ DA9055_ADC_VSYS);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, da9055_read_auto_ch, NULL,
+ DA9055_ADC_ADCIN1);
+static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_label, NULL,
+ DA9055_ADC_ADCIN1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, da9055_read_auto_ch, NULL,
+ DA9055_ADC_ADCIN2);
+static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_label, NULL,
+ DA9055_ADC_ADCIN2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, da9055_read_auto_ch, NULL,
+ DA9055_ADC_ADCIN3);
+static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL,
+ DA9055_ADC_ADCIN3);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, da9055_read_tjunc, NULL,
+ DA9055_ADC_TJUNC);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL,
+ DA9055_ADC_TJUNC);
+
+static DEVICE_ATTR(name, S_IRUGO, da9055_hwmon_show_name, NULL);
+
+static struct attribute *da9055_attr[] = {
+ &dev_attr_name.attr,
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_label.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_label.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_label.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_label.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_label.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group da9055_attr_group = {.attrs = da9055_attr};
+
+static int da9055_hwmon_probe(struct platform_device *pdev)
+{
+ struct da9055_hwmon *hwmon;
+ int hwmon_irq, ret;
+
+ hwmon = devm_kzalloc(&pdev->dev, sizeof(struct da9055_hwmon),
+ GFP_KERNEL);
+ if (!hwmon)
+ return -ENOMEM;
+
+ mutex_init(&hwmon->hwmon_lock);
+ mutex_init(&hwmon->irq_lock);
+
+ init_completion(&hwmon->done);
+ hwmon->da9055 = dev_get_drvdata(pdev->dev.parent);
+
+ platform_set_drvdata(pdev, hwmon);
+
+ hwmon_irq = platform_get_irq_byname(pdev, "HWMON");
+ if (hwmon_irq < 0)
+ return hwmon_irq;
+
+ hwmon_irq = regmap_irq_get_virq(hwmon->da9055->irq_data, hwmon_irq);
+ if (hwmon_irq < 0)
+ return hwmon_irq;
+
+ ret = devm_request_threaded_irq(&pdev->dev, hwmon_irq,
+ NULL, da9055_auxadc_irq,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ "adc-irq", hwmon);
+ if (ret != 0) {
+ dev_err(hwmon->da9055->dev, "DA9055 ADC IRQ failed ret=%d\n",
+ ret);
+ return ret;
+ }
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &da9055_attr_group);
+ if (ret)
+ return ret;
+
+ hwmon->class_device = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(hwmon->class_device)) {
+ ret = PTR_ERR(hwmon->class_device);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ sysfs_remove_group(&pdev->dev.kobj, &da9055_attr_group);
+ return ret;
+}
+
+static int da9055_hwmon_remove(struct platform_device *pdev)
+{
+ struct da9055_hwmon *hwmon = platform_get_drvdata(pdev);
+
+ sysfs_remove_group(&pdev->dev.kobj, &da9055_attr_group);
+ hwmon_device_unregister(hwmon->class_device);
+
+ return 0;
+}
+
+static struct platform_driver da9055_hwmon_driver = {
+ .probe = da9055_hwmon_probe,
+ .remove = da9055_hwmon_remove,
+ .driver = {
+ .name = "da9055-hwmon",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(da9055_hwmon_driver);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("DA9055 HWMON driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9055-hwmon");
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c
index 4f4110407387..34ab2a8f9654 100644
--- a/drivers/hwmon/fam15h_power.c
+++ b/drivers/hwmon/fam15h_power.c
@@ -31,6 +31,9 @@ MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor");
MODULE_AUTHOR("Andreas Herrmann <herrmann.der.user@googlemail.com>");
MODULE_LICENSE("GPL");
+/* Family 16h Northbridge's function 4 PCI ID */
+#define PCI_DEVICE_ID_AMD_16H_NB_F4 0x1534
+
/* D18F3 */
#define REG_NORTHBRIDGE_CAP 0xe8
@@ -248,6 +251,7 @@ static void __devexit fam15h_power_remove(struct pci_dev *pdev)
static DEFINE_PCI_DEVICE_TABLE(fam15h_power_id_table) = {
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
{}
};
MODULE_DEVICE_TABLE(pci, fam15h_power_id_table);
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 2b726346f8fa..8e7158c3ad2f 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -302,19 +302,8 @@ static struct i2c_driver ina2xx_driver = {
.id_table = ina2xx_id,
};
-static int __init ina2xx_init(void)
-{
- return i2c_add_driver(&ina2xx_driver);
-}
-
-static void __exit ina2xx_exit(void)
-{
- i2c_del_driver(&ina2xx_driver);
-}
+module_i2c_driver(ina2xx_driver);
MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>");
MODULE_DESCRIPTION("ina2xx driver");
MODULE_LICENSE("GPL");
-
-module_init(ina2xx_init);
-module_exit(ina2xx_exit);
diff --git a/drivers/input/matrix-keymap.c b/drivers/input/matrix-keymap.c
index 443ad64b7f2a..d88d9be1d1b7 100644
--- a/drivers/input/matrix-keymap.c
+++ b/drivers/input/matrix-keymap.c
@@ -23,6 +23,7 @@
#include <linux/input.h>
#include <linux/of.h>
#include <linux/export.h>
+#include <linux/module.h>
#include <linux/input/matrix_keypad.h>
static bool matrix_keypad_map_key(struct input_dev *input_dev,
@@ -161,3 +162,5 @@ int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
return 0;
}
EXPORT_SYMBOL(matrix_keypad_build_keymap);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 636bae0405e8..a0f73092176e 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -963,7 +963,7 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule)
struct r1conf *conf = mddev->private;
struct bio *bio;
- if (from_schedule) {
+ if (from_schedule || current->bio_list) {
spin_lock_irq(&conf->device_lock);
bio_list_merge(&conf->pending_bio_list, &plug->pending);
conf->pending_count += plug->pending_cnt;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 0d5d0ff2c0f7..c9acbd717131 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1069,7 +1069,7 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule)
struct r10conf *conf = mddev->private;
struct bio *bio;
- if (from_schedule) {
+ if (from_schedule || current->bio_list) {
spin_lock_irq(&conf->device_lock);
bio_list_merge(&conf->pending_bio_list, &plug->pending);
conf->pending_count += plug->pending_cnt;
diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c
index 262dfa503c2a..b551ca350e00 100644
--- a/drivers/media/dvb-frontends/stv0900_core.c
+++ b/drivers/media/dvb-frontends/stv0900_core.c
@@ -300,15 +300,15 @@ static enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *intp, u32
{
u32 m_div, clk_sel;
- dprintk("%s: Mclk set to %d, Quartz = %d\n", __func__, mclk,
- intp->quartz);
-
if (intp == NULL)
return STV0900_INVALID_HANDLE;
if (intp->errs)
return STV0900_I2C_ERROR;
+ dprintk("%s: Mclk set to %d, Quartz = %d\n", __func__, mclk,
+ intp->quartz);
+
clk_sel = ((stv0900_get_bits(intp, F0900_SELX1RATIO) == 1) ? 4 : 6);
m_div = ((clk_sel * mclk) / intp->quartz) - 1;
stv0900_write_bits(intp, F0900_M_DIV, m_div);
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 109bc9b12e74..05f8950f6f91 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -53,8 +53,7 @@ MODULE_LICENSE("GPL");
/* ADV7604 system clock frequency */
#define ADV7604_fsc (28636360)
-#define DIGITAL_INPUT ((state->prim_mode == ADV7604_PRIM_MODE_HDMI_COMP) || \
- (state->prim_mode == ADV7604_PRIM_MODE_HDMI_GR))
+#define DIGITAL_INPUT (state->mode == ADV7604_MODE_HDMI)
/*
**********************************************************************
@@ -68,7 +67,7 @@ struct adv7604_state {
struct v4l2_subdev sd;
struct media_pad pad;
struct v4l2_ctrl_handler hdl;
- enum adv7604_prim_mode prim_mode;
+ enum adv7604_mode mode;
struct v4l2_dv_timings timings;
u8 edid[256];
unsigned edid_blocks;
@@ -77,6 +76,7 @@ struct adv7604_state {
struct workqueue_struct *work_queues;
struct delayed_work delayed_work_enable_hotplug;
bool connector_hdmi;
+ bool restart_stdi_once;
/* i2c clients */
struct i2c_client *i2c_avlink;
@@ -106,7 +106,6 @@ static const struct v4l2_dv_timings adv7604_timings[] = {
V4L2_DV_BT_CEA_720X576P50,
V4L2_DV_BT_CEA_1280X720P24,
V4L2_DV_BT_CEA_1280X720P25,
- V4L2_DV_BT_CEA_1280X720P30,
V4L2_DV_BT_CEA_1280X720P50,
V4L2_DV_BT_CEA_1280X720P60,
V4L2_DV_BT_CEA_1920X1080P24,
@@ -115,6 +114,7 @@ static const struct v4l2_dv_timings adv7604_timings[] = {
V4L2_DV_BT_CEA_1920X1080P50,
V4L2_DV_BT_CEA_1920X1080P60,
+ /* sorted by DMT ID */
V4L2_DV_BT_DMT_640X350P85,
V4L2_DV_BT_DMT_640X400P85,
V4L2_DV_BT_DMT_720X400P85,
@@ -164,6 +164,89 @@ static const struct v4l2_dv_timings adv7604_timings[] = {
{ },
};
+struct adv7604_video_standards {
+ struct v4l2_dv_timings timings;
+ u8 vid_std;
+ u8 v_freq;
+};
+
+/* sorted by number of lines */
+static const struct adv7604_video_standards adv7604_prim_mode_comp[] = {
+ /* { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, TODO flickering */
+ { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 },
+ { V4L2_DV_BT_CEA_1280X720P50, 0x19, 0x01 },
+ { V4L2_DV_BT_CEA_1280X720P60, 0x19, 0x00 },
+ { V4L2_DV_BT_CEA_1920X1080P24, 0x1e, 0x04 },
+ { V4L2_DV_BT_CEA_1920X1080P25, 0x1e, 0x03 },
+ { V4L2_DV_BT_CEA_1920X1080P30, 0x1e, 0x02 },
+ { V4L2_DV_BT_CEA_1920X1080P50, 0x1e, 0x01 },
+ { V4L2_DV_BT_CEA_1920X1080P60, 0x1e, 0x00 },
+ /* TODO add 1920x1080P60_RB (CVT timing) */
+ { },
+};
+
+/* sorted by number of lines */
+static const struct adv7604_video_standards adv7604_prim_mode_gr[] = {
+ { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 },
+ { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 },
+ { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 },
+ { V4L2_DV_BT_DMT_640X480P85, 0x0b, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P56, 0x00, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P60, 0x01, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P72, 0x02, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P75, 0x03, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P85, 0x04, 0x00 },
+ { V4L2_DV_BT_DMT_1024X768P60, 0x0c, 0x00 },
+ { V4L2_DV_BT_DMT_1024X768P70, 0x0d, 0x00 },
+ { V4L2_DV_BT_DMT_1024X768P75, 0x0e, 0x00 },
+ { V4L2_DV_BT_DMT_1024X768P85, 0x0f, 0x00 },
+ { V4L2_DV_BT_DMT_1280X1024P60, 0x05, 0x00 },
+ { V4L2_DV_BT_DMT_1280X1024P75, 0x06, 0x00 },
+ { V4L2_DV_BT_DMT_1360X768P60, 0x12, 0x00 },
+ { V4L2_DV_BT_DMT_1366X768P60, 0x13, 0x00 },
+ { V4L2_DV_BT_DMT_1400X1050P60, 0x14, 0x00 },
+ { V4L2_DV_BT_DMT_1400X1050P75, 0x15, 0x00 },
+ { V4L2_DV_BT_DMT_1600X1200P60, 0x16, 0x00 }, /* TODO not tested */
+ /* TODO add 1600X1200P60_RB (not a DMT timing) */
+ { V4L2_DV_BT_DMT_1680X1050P60, 0x18, 0x00 },
+ { V4L2_DV_BT_DMT_1920X1200P60_RB, 0x19, 0x00 }, /* TODO not tested */
+ { },
+};
+
+/* sorted by number of lines */
+static const struct adv7604_video_standards adv7604_prim_mode_hdmi_comp[] = {
+ { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 },
+ { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 },
+ { V4L2_DV_BT_CEA_1280X720P50, 0x13, 0x01 },
+ { V4L2_DV_BT_CEA_1280X720P60, 0x13, 0x00 },
+ { V4L2_DV_BT_CEA_1920X1080P24, 0x1e, 0x04 },
+ { V4L2_DV_BT_CEA_1920X1080P25, 0x1e, 0x03 },
+ { V4L2_DV_BT_CEA_1920X1080P30, 0x1e, 0x02 },
+ { V4L2_DV_BT_CEA_1920X1080P50, 0x1e, 0x01 },
+ { V4L2_DV_BT_CEA_1920X1080P60, 0x1e, 0x00 },
+ { },
+};
+
+/* sorted by number of lines */
+static const struct adv7604_video_standards adv7604_prim_mode_hdmi_gr[] = {
+ { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 },
+ { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 },
+ { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 },
+ { V4L2_DV_BT_DMT_640X480P85, 0x0b, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P56, 0x00, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P60, 0x01, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P72, 0x02, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P75, 0x03, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P85, 0x04, 0x00 },
+ { V4L2_DV_BT_DMT_1024X768P60, 0x0c, 0x00 },
+ { V4L2_DV_BT_DMT_1024X768P70, 0x0d, 0x00 },
+ { V4L2_DV_BT_DMT_1024X768P75, 0x0e, 0x00 },
+ { V4L2_DV_BT_DMT_1024X768P85, 0x0f, 0x00 },
+ { V4L2_DV_BT_DMT_1280X1024P60, 0x05, 0x00 },
+ { V4L2_DV_BT_DMT_1280X1024P75, 0x06, 0x00 },
+ { },
+};
+
/* ----------------------------------------------------------------------- */
static inline struct adv7604_state *to_state(struct v4l2_subdev *sd)
@@ -672,64 +755,144 @@ static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd)
((io_read(sd, 0x6f) & 0x10) >> 4));
}
-static void configure_free_run(struct v4l2_subdev *sd, const struct v4l2_bt_timings *timings)
+static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd,
+ u8 prim_mode,
+ const struct adv7604_video_standards *predef_vid_timings,
+ const struct v4l2_dv_timings *timings)
+{
+ struct adv7604_state *state = to_state(sd);
+ int i;
+
+ for (i = 0; predef_vid_timings[i].timings.bt.width; i++) {
+ if (!v4l_match_dv_timings(timings, &predef_vid_timings[i].timings,
+ DIGITAL_INPUT ? 250000 : 1000000))
+ continue;
+ io_write(sd, 0x00, predef_vid_timings[i].vid_std); /* video std */
+ io_write(sd, 0x01, (predef_vid_timings[i].v_freq << 4) +
+ prim_mode); /* v_freq and prim mode */
+ return 0;
+ }
+
+ return -1;
+}
+
+static int configure_predefined_video_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *timings)
{
+ struct adv7604_state *state = to_state(sd);
+ int err;
+
+ v4l2_dbg(1, debug, sd, "%s", __func__);
+
+ /* reset to default values */
+ io_write(sd, 0x16, 0x43);
+ io_write(sd, 0x17, 0x5a);
+ /* disable embedded syncs for auto graphics mode */
+ cp_write_and_or(sd, 0x81, 0xef, 0x00);
+ cp_write(sd, 0x8f, 0x00);
+ cp_write(sd, 0x90, 0x00);
+ cp_write(sd, 0xa2, 0x00);
+ cp_write(sd, 0xa3, 0x00);
+ cp_write(sd, 0xa4, 0x00);
+ cp_write(sd, 0xa5, 0x00);
+ cp_write(sd, 0xa6, 0x00);
+ cp_write(sd, 0xa7, 0x00);
+ cp_write(sd, 0xab, 0x00);
+ cp_write(sd, 0xac, 0x00);
+
+ switch (state->mode) {
+ case ADV7604_MODE_COMP:
+ case ADV7604_MODE_GR:
+ err = find_and_set_predefined_video_timings(sd,
+ 0x01, adv7604_prim_mode_comp, timings);
+ if (err)
+ err = find_and_set_predefined_video_timings(sd,
+ 0x02, adv7604_prim_mode_gr, timings);
+ break;
+ case ADV7604_MODE_HDMI:
+ err = find_and_set_predefined_video_timings(sd,
+ 0x05, adv7604_prim_mode_hdmi_comp, timings);
+ if (err)
+ err = find_and_set_predefined_video_timings(sd,
+ 0x06, adv7604_prim_mode_hdmi_gr, timings);
+ break;
+ default:
+ v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n",
+ __func__, state->mode);
+ err = -1;
+ break;
+ }
+
+
+ return err;
+}
+
+static void configure_custom_video_timings(struct v4l2_subdev *sd,
+ const struct v4l2_bt_timings *bt)
+{
+ struct adv7604_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
- u32 width = htotal(timings);
- u32 height = vtotal(timings);
- u16 ch1_fr_ll = (((u32)timings->pixelclock / 100) > 0) ?
- ((width * (ADV7604_fsc / 100)) / ((u32)timings->pixelclock / 100)) : 0;
+ u32 width = htotal(bt);
+ u32 height = vtotal(bt);
+ u16 cp_start_sav = bt->hsync + bt->hbackporch - 4;
+ u16 cp_start_eav = width - bt->hfrontporch;
+ u16 cp_start_vbi = height - bt->vfrontporch;
+ u16 cp_end_vbi = bt->vsync + bt->vbackporch;
+ u16 ch1_fr_ll = (((u32)bt->pixelclock / 100) > 0) ?
+ ((width * (ADV7604_fsc / 100)) / ((u32)bt->pixelclock / 100)) : 0;
+ const u8 pll[2] = {
+ 0xc0 | ((width >> 8) & 0x1f),
+ width & 0xff
+ };
v4l2_dbg(2, debug, sd, "%s\n", __func__);
- cp_write(sd, 0x8f, (ch1_fr_ll >> 8) & 0x7); /* CH1_FR_LL */
- cp_write(sd, 0x90, ch1_fr_ll & 0xff); /* CH1_FR_LL */
- cp_write(sd, 0xab, (height >> 4) & 0xff); /* CP_LCOUNT_MAX */
- cp_write(sd, 0xac, (height & 0x0f) << 4); /* CP_LCOUNT_MAX */
- /* TODO support interlaced */
- cp_write(sd, 0x91, 0x10); /* INTERLACED */
-
- /* Should only be set in auto-graphics mode [REF_02 p. 91-92] */
- if ((io_read(sd, 0x00) == 0x07) && (io_read(sd, 0x01) == 0x02)) {
- u16 cp_start_sav, cp_start_eav, cp_start_vbi, cp_end_vbi;
- const u8 pll[2] = {
- (0xc0 | ((width >> 8) & 0x1f)),
- (width & 0xff)
- };
+ switch (state->mode) {
+ case ADV7604_MODE_COMP:
+ case ADV7604_MODE_GR:
+ /* auto graphics */
+ io_write(sd, 0x00, 0x07); /* video std */
+ io_write(sd, 0x01, 0x02); /* prim mode */
+ /* enable embedded syncs for auto graphics mode */
+ cp_write_and_or(sd, 0x81, 0xef, 0x10);
+ /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */
/* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */
/* IO-map reg. 0x16 and 0x17 should be written in sequence */
if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll)) {
v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n");
- return;
+ break;
}
/* active video - horizontal timing */
- cp_start_sav = timings->hsync + timings->hbackporch - 4;
- cp_start_eav = width - timings->hfrontporch;
cp_write(sd, 0xa2, (cp_start_sav >> 4) & 0xff);
- cp_write(sd, 0xa3, ((cp_start_sav & 0x0f) << 4) | ((cp_start_eav >> 8) & 0x0f));
+ cp_write(sd, 0xa3, ((cp_start_sav & 0x0f) << 4) |
+ ((cp_start_eav >> 8) & 0x0f));
cp_write(sd, 0xa4, cp_start_eav & 0xff);
/* active video - vertical timing */
- cp_start_vbi = height - timings->vfrontporch;
- cp_end_vbi = timings->vsync + timings->vbackporch;
cp_write(sd, 0xa5, (cp_start_vbi >> 4) & 0xff);
- cp_write(sd, 0xa6, ((cp_start_vbi & 0xf) << 4) | ((cp_end_vbi >> 8) & 0xf));
+ cp_write(sd, 0xa6, ((cp_start_vbi & 0xf) << 4) |
+ ((cp_end_vbi >> 8) & 0xf));
cp_write(sd, 0xa7, cp_end_vbi & 0xff);
- } else {
- /* reset to default values */
- io_write(sd, 0x16, 0x43);
- io_write(sd, 0x17, 0x5a);
- cp_write(sd, 0xa2, 0x00);
- cp_write(sd, 0xa3, 0x00);
- cp_write(sd, 0xa4, 0x00);
- cp_write(sd, 0xa5, 0x00);
- cp_write(sd, 0xa6, 0x00);
- cp_write(sd, 0xa7, 0x00);
+ break;
+ case ADV7604_MODE_HDMI:
+ /* set default prim_mode/vid_std for HDMI
+ accoring to [REF_03, c. 4.2] */
+ io_write(sd, 0x00, 0x02); /* video std */
+ io_write(sd, 0x01, 0x06); /* prim mode */
+ break;
+ default:
+ v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n",
+ __func__, state->mode);
+ break;
}
-}
+ cp_write(sd, 0x8f, (ch1_fr_ll >> 8) & 0x7);
+ cp_write(sd, 0x90, ch1_fr_ll & 0xff);
+ cp_write(sd, 0xab, (height >> 4) & 0xff);
+ cp_write(sd, 0xac, (height & 0x0f) << 4);
+}
static void set_rgb_quantization_range(struct v4l2_subdev *sd)
{
@@ -738,12 +901,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
switch (state->rgb_quantization_range) {
case V4L2_DV_RGB_RANGE_AUTO:
/* automatic */
- if ((hdmi_read(sd, 0x05) & 0x80) ||
- (state->prim_mode == ADV7604_PRIM_MODE_COMP) ||
- (state->prim_mode == ADV7604_PRIM_MODE_RGB)) {
- /* receiving HDMI or analog signal */
- io_write_and_or(sd, 0x02, 0x0f, 0xf0);
- } else {
+ if (DIGITAL_INPUT && !(hdmi_read(sd, 0x05) & 0x80)) {
/* receiving DVI-D signal */
/* ADV7604 selects RGB limited range regardless of
@@ -756,6 +914,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
/* RGB full range (0-255) */
io_write_and_or(sd, 0x02, 0x0f, 0x10);
}
+ } else {
+ /* receiving HDMI or analog signal, set automode */
+ io_write_and_or(sd, 0x02, 0x0f, 0xf0);
}
break;
case V4L2_DV_RGB_RANGE_LIMITED:
@@ -967,8 +1128,10 @@ static int stdi2dv_timings(struct v4l2_subdev *sd,
state->aspect_ratio, timings))
return 0;
- v4l2_dbg(2, debug, sd, "%s: No format candidate found for lcf=%d, bl = %d\n",
- __func__, stdi->lcf, stdi->bl);
+ v4l2_dbg(2, debug, sd,
+ "%s: No format candidate found for lcvs = %d, lcf=%d, bl = %d, %chsync, %cvsync\n",
+ __func__, stdi->lcvs, stdi->lcf, stdi->bl,
+ stdi->hs_pol, stdi->vs_pol);
return -1;
}
@@ -1123,7 +1286,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd,
adv7604_fill_optional_dv_timings_fields(sd, timings);
} else {
/* find format
- * Since LCVS values are inaccurate (REF_03, page 275-276),
+ * Since LCVS values are inaccurate [REF_03, p. 275-276],
* stdi2dv_timings() is called with lcvs +-1 if the first attempt fails.
*/
if (!stdi2dv_timings(sd, &stdi, timings))
@@ -1135,9 +1298,31 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd,
stdi.lcvs -= 2;
v4l2_dbg(1, debug, sd, "%s: lcvs - 1 = %d\n", __func__, stdi.lcvs);
if (stdi2dv_timings(sd, &stdi, timings)) {
+ /*
+ * The STDI block may measure wrong values, especially
+ * for lcvs and lcf. If the driver can not find any
+ * valid timing, the STDI block is restarted to measure
+ * the video timings again. The function will return an
+ * error, but the restart of STDI will generate a new
+ * STDI interrupt and the format detection process will
+ * restart.
+ */
+ if (state->restart_stdi_once) {
+ v4l2_dbg(1, debug, sd, "%s: restart STDI\n", __func__);
+ /* TODO restart STDI for Sync Channel 2 */
+ /* enter one-shot mode */
+ cp_write_and_or(sd, 0x86, 0xf9, 0x00);
+ /* trigger STDI restart */
+ cp_write_and_or(sd, 0x86, 0xf9, 0x04);
+ /* reset to continuous mode */
+ cp_write_and_or(sd, 0x86, 0xf9, 0x02);
+ state->restart_stdi_once = false;
+ return -ENOLINK;
+ }
v4l2_dbg(1, debug, sd, "%s: format not supported\n", __func__);
return -ERANGE;
}
+ state->restart_stdi_once = true;
}
found:
@@ -1166,6 +1351,7 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd,
{
struct adv7604_state *state = to_state(sd);
struct v4l2_bt_timings *bt;
+ int err;
if (!timings)
return -EINVAL;
@@ -1178,12 +1364,20 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd,
__func__, (u32)bt->pixelclock);
return -ERANGE;
}
+
adv7604_fill_optional_dv_timings_fields(sd, timings);
state->timings = *timings;
- /* freerun */
- configure_free_run(sd, bt);
+ cp_write(sd, 0x91, bt->interlaced ? 0x50 : 0x10);
+
+ /* Use prim_mode and vid_std when available */
+ err = configure_predefined_video_timings(sd, timings);
+ if (err) {
+ /* custom settings when the video format
+ does not have prim_mode/vid_std */
+ configure_custom_video_timings(sd, bt);
+ }
set_rgb_quantization_range(sd);
@@ -1203,24 +1397,25 @@ static int adv7604_g_dv_timings(struct v4l2_subdev *sd,
return 0;
}
-static void enable_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mode)
+static void enable_input(struct v4l2_subdev *sd)
{
- switch (prim_mode) {
- case ADV7604_PRIM_MODE_COMP:
- case ADV7604_PRIM_MODE_RGB:
+ struct adv7604_state *state = to_state(sd);
+
+ switch (state->mode) {
+ case ADV7604_MODE_COMP:
+ case ADV7604_MODE_GR:
/* enable */
io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */
break;
- case ADV7604_PRIM_MODE_HDMI_COMP:
- case ADV7604_PRIM_MODE_HDMI_GR:
+ case ADV7604_MODE_HDMI:
/* enable */
hdmi_write(sd, 0x1a, 0x0a); /* Unmute audio */
hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */
io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */
break;
default:
- v4l2_err(sd, "%s: reserved primary mode 0x%0x\n",
- __func__, prim_mode);
+ v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n",
+ __func__, state->mode);
break;
}
}
@@ -1233,17 +1428,13 @@ static void disable_input(struct v4l2_subdev *sd)
hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */
}
-static void select_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mode)
+static void select_input(struct v4l2_subdev *sd)
{
- switch (prim_mode) {
- case ADV7604_PRIM_MODE_COMP:
- case ADV7604_PRIM_MODE_RGB:
- /* set mode and select free run resolution */
- io_write(sd, 0x00, 0x07); /* video std */
- io_write(sd, 0x01, 0x02); /* prim mode */
- /* enable embedded syncs for auto graphics mode */
- cp_write_and_or(sd, 0x81, 0xef, 0x10);
+ struct adv7604_state *state = to_state(sd);
+ switch (state->mode) {
+ case ADV7604_MODE_COMP:
+ case ADV7604_MODE_GR:
/* reset ADI recommended settings for HDMI: */
/* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */
hdmi_write(sd, 0x0d, 0x04); /* HDMI filter optimization */
@@ -1271,16 +1462,7 @@ static void select_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mod
cp_write(sd, 0x40, 0x5c); /* CP core pre-gain control. Graphics mode */
break;
- case ADV7604_PRIM_MODE_HDMI_COMP:
- case ADV7604_PRIM_MODE_HDMI_GR:
- /* set mode and select free run resolution */
- /* video std */
- io_write(sd, 0x00,
- (prim_mode == ADV7604_PRIM_MODE_HDMI_GR) ? 0x02 : 0x1e);
- io_write(sd, 0x01, prim_mode); /* prim mode */
- /* disable embedded syncs for auto graphics mode */
- cp_write_and_or(sd, 0x81, 0xef, 0x00);
-
+ case ADV7604_MODE_HDMI:
/* set ADI recommended settings for HDMI: */
/* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */
hdmi_write(sd, 0x0d, 0x84); /* HDMI filter optimization */
@@ -1309,7 +1491,8 @@ static void select_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mod
break;
default:
- v4l2_err(sd, "%s: reserved primary mode 0x%0x\n", __func__, prim_mode);
+ v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n",
+ __func__, state->mode);
break;
}
}
@@ -1321,26 +1504,13 @@ static int adv7604_s_routing(struct v4l2_subdev *sd,
v4l2_dbg(2, debug, sd, "%s: input %d", __func__, input);
- switch (input) {
- case 0:
- /* TODO select HDMI_COMP or HDMI_GR */
- state->prim_mode = ADV7604_PRIM_MODE_HDMI_COMP;
- break;
- case 1:
- state->prim_mode = ADV7604_PRIM_MODE_RGB;
- break;
- case 2:
- state->prim_mode = ADV7604_PRIM_MODE_COMP;
- break;
- default:
- return -EINVAL;
- }
+ state->mode = input;
disable_input(sd);
- select_input(sd, state->prim_mode);
+ select_input(sd);
- enable_input(sd, state->prim_mode);
+ enable_input(sd);
return 0;
}
@@ -1549,8 +1719,9 @@ static int adv7604_log_status(struct v4l2_subdev *sd)
v4l2_info(sd, "CP locked: %s\n", no_lock_cp(sd) ? "false" : "true");
v4l2_info(sd, "CP free run: %s\n",
(!!(cp_read(sd, 0xff) & 0x10) ? "on" : "off"));
- v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x\n",
- io_read(sd, 0x01) & 0x0f, io_read(sd, 0x00) & 0x3f);
+ v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x, v_freq = 0x%x\n",
+ io_read(sd, 0x01) & 0x0f, io_read(sd, 0x00) & 0x3f,
+ (io_read(sd, 0x01) & 0x70) >> 4);
v4l2_info(sd, "-----Video Timings-----\n");
if (read_stdi(sd, &stdi))
@@ -1712,9 +1883,9 @@ static int adv7604_core_init(struct v4l2_subdev *sd)
cp_write(sd, 0xba, (pdata->hdmi_free_run_mode << 1) | 0x01); /* HDMI free run */
cp_write(sd, 0xf3, 0xdc); /* Low threshold to enter/exit free run mode */
cp_write(sd, 0xf9, 0x23); /* STDI ch. 1 - LCVS change threshold -
- ADI recommended setting [REF_01 c. 2.3.3] */
+ ADI recommended setting [REF_01, c. 2.3.3] */
cp_write(sd, 0x45, 0x23); /* STDI ch. 2 - LCVS change threshold -
- ADI recommended setting [REF_01 c. 2.3.3] */
+ ADI recommended setting [REF_01, c. 2.3.3] */
cp_write(sd, 0xc9, 0x2d); /* use prim_mode and vid_std as free run resolution
for digital formats */
@@ -1724,11 +1895,6 @@ static int adv7604_core_init(struct v4l2_subdev *sd)
afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */
io_write_and_or(sd, 0x30, ~(1 << 4), pdata->output_bus_lsb_to_msb << 4);
- state->prim_mode = pdata->prim_mode;
- select_input(sd, pdata->prim_mode);
-
- enable_input(sd, pdata->prim_mode);
-
/* interrupts */
io_write(sd, 0x40, 0xc2); /* Configure INT1 */
io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */
@@ -1883,6 +2049,7 @@ static int adv7604_probe(struct i2c_client *client,
v4l2_err(sd, "failed to create all i2c clients\n");
goto err_i2c;
}
+ state->restart_stdi_once = true;
/* work queues */
state->work_queues = create_singlethread_workqueue(client->name);
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c
index 13057b966ee9..333ef178d6fb 100644
--- a/drivers/media/i2c/soc_camera/mt9v022.c
+++ b/drivers/media/i2c/soc_camera/mt9v022.c
@@ -263,9 +263,14 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
if (ret & 1) /* Autoexposure */
ret = reg_write(client, mt9v022->reg->max_total_shutter_width,
rect.height + mt9v022->y_skip_top + 43);
- else
- ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
- rect.height + mt9v022->y_skip_top + 43);
+ /*
+ * If autoexposure is off, there is no need to set
+ * MT9V022_TOTAL_SHUTTER_WIDTH here. Autoexposure can be off
+ * only if the user has set exposure manually, using the
+ * V4L2_CID_EXPOSURE_AUTO with the value V4L2_EXPOSURE_MANUAL.
+ * In this case the register MT9V022_TOTAL_SHUTTER_WIDTH
+ * already contains the correct value.
+ */
}
/* Setup frame format: defaults apart from width and height */
if (!ret)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index bfec9e65aefb..19cbb12a12a2 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -965,8 +965,10 @@ static struct platform_device_id gsc_driver_ids[] = {
MODULE_DEVICE_TABLE(platform, gsc_driver_ids);
static const struct of_device_id exynos_gsc_match[] = {
- { .compatible = "samsung,exynos5250-gsc",
- .data = &gsc_v_100_drvdata, },
+ {
+ .compatible = "samsung,exynos5-gsc",
+ .data = &gsc_v_100_drvdata,
+ },
{},
};
MODULE_DEVICE_TABLE(of, exynos_gsc_match);
diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c
index 3c7f00577bd9..c065d040ed94 100644
--- a/drivers/media/platform/exynos-gsc/gsc-m2m.c
+++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c
@@ -657,8 +657,7 @@ static int gsc_m2m_release(struct file *file)
pr_debug("pid: %d, state: 0x%lx, refcnt= %d",
task_pid_nr(current), gsc->state, gsc->m2m.refcnt);
- if (mutex_lock_interruptible(&gsc->lock))
- return -ERESTARTSYS;
+ mutex_lock(&gsc->lock);
v4l2_m2m_ctx_release(ctx->m2m_ctx);
gsc_ctrls_delete(ctx);
@@ -732,6 +731,7 @@ int gsc_register_m2m_device(struct gsc_dev *gsc)
gsc->vdev.ioctl_ops = &gsc_m2m_ioctl_ops;
gsc->vdev.release = video_device_release_empty;
gsc->vdev.lock = &gsc->lock;
+ gsc->vdev.vfl_dir = VFL_DIR_M2M;
snprintf(gsc->vdev.name, sizeof(gsc->vdev.name), "%s.%d:m2m",
GSC_MODULE_NAME, gsc->id);
diff --git a/drivers/media/platform/exynos-gsc/gsc-regs.h b/drivers/media/platform/exynos-gsc/gsc-regs.h
index 533e9947a925..4678f9a6a4fd 100644
--- a/drivers/media/platform/exynos-gsc/gsc-regs.h
+++ b/drivers/media/platform/exynos-gsc/gsc-regs.h
@@ -40,10 +40,10 @@
#define GSC_IN_ROT_YFLIP (2 << 16)
#define GSC_IN_ROT_XFLIP (1 << 16)
#define GSC_IN_RGB_TYPE_MASK (3 << 14)
-#define GSC_IN_RGB_HD_WIDE (3 << 14)
-#define GSC_IN_RGB_HD_NARROW (2 << 14)
-#define GSC_IN_RGB_SD_WIDE (1 << 14)
-#define GSC_IN_RGB_SD_NARROW (0 << 14)
+#define GSC_IN_RGB_HD_NARROW (3 << 14)
+#define GSC_IN_RGB_HD_WIDE (2 << 14)
+#define GSC_IN_RGB_SD_NARROW (1 << 14)
+#define GSC_IN_RGB_SD_WIDE (0 << 14)
#define GSC_IN_YUV422_1P_ORDER_MASK (1 << 13)
#define GSC_IN_YUV422_1P_ORDER_LSB_Y (0 << 13)
#define GSC_IN_YUV422_1P_OEDER_LSB_C (1 << 13)
@@ -85,10 +85,10 @@
#define GSC_OUT_GLOBAL_ALPHA_MASK (0xff << 24)
#define GSC_OUT_GLOBAL_ALPHA(x) ((x) << 24)
#define GSC_OUT_RGB_TYPE_MASK (3 << 10)
-#define GSC_OUT_RGB_HD_NARROW (3 << 10)
-#define GSC_OUT_RGB_HD_WIDE (2 << 10)
-#define GSC_OUT_RGB_SD_NARROW (1 << 10)
-#define GSC_OUT_RGB_SD_WIDE (0 << 10)
+#define GSC_OUT_RGB_HD_WIDE (3 << 10)
+#define GSC_OUT_RGB_HD_NARROW (2 << 10)
+#define GSC_OUT_RGB_SD_WIDE (1 << 10)
+#define GSC_OUT_RGB_SD_NARROW (0 << 10)
#define GSC_OUT_YUV422_1P_ORDER_MASK (1 << 9)
#define GSC_OUT_YUV422_1P_ORDER_LSB_Y (0 << 9)
#define GSC_OUT_YUV422_1P_OEDER_LSB_C (1 << 9)
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
index 60181ab96063..aa9df9d71a7b 100644
--- a/drivers/media/platform/omap3isp/ispccdc.c
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -1706,7 +1706,7 @@ static long ccdc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
}
static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
- const struct v4l2_event_subscription *sub)
+ struct v4l2_event_subscription *sub)
{
if (sub->type != V4L2_EVENT_FRAME_SYNC)
return -EINVAL;
@@ -1719,7 +1719,7 @@ static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
}
static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
- const struct v4l2_event_subscription *sub)
+ struct v4l2_event_subscription *sub)
{
return v4l2_event_unsubscribe(fh, sub);
}
diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c
index d7ac76b5c2ae..b8640be692f1 100644
--- a/drivers/media/platform/omap3isp/ispstat.c
+++ b/drivers/media/platform/omap3isp/ispstat.c
@@ -1025,7 +1025,7 @@ void omap3isp_stat_dma_isr(struct ispstat *stat)
int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev,
struct v4l2_fh *fh,
- const struct v4l2_event_subscription *sub)
+ struct v4l2_event_subscription *sub)
{
struct ispstat *stat = v4l2_get_subdevdata(subdev);
@@ -1037,7 +1037,7 @@ int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev,
int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev,
struct v4l2_fh *fh,
- const struct v4l2_event_subscription *sub)
+ struct v4l2_event_subscription *sub)
{
return v4l2_event_unsubscribe(fh, sub);
}
diff --git a/drivers/media/platform/omap3isp/ispstat.h b/drivers/media/platform/omap3isp/ispstat.h
index a6fe653eb237..9b7c8654dc8a 100644
--- a/drivers/media/platform/omap3isp/ispstat.h
+++ b/drivers/media/platform/omap3isp/ispstat.h
@@ -147,10 +147,10 @@ int omap3isp_stat_init(struct ispstat *stat, const char *name,
void omap3isp_stat_cleanup(struct ispstat *stat);
int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev,
struct v4l2_fh *fh,
- const struct v4l2_event_subscription *sub);
+ struct v4l2_event_subscription *sub);
int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev,
struct v4l2_fh *fh,
- const struct v4l2_event_subscription *sub);
+ struct v4l2_event_subscription *sub);
int omap3isp_stat_s_stream(struct v4l2_subdev *subdev, int enable);
int omap3isp_stat_busy(struct ispstat *stat);
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index a0b737fecf13..75cd309035f9 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -792,7 +792,7 @@ isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop)
}
static int
-isp_video_set_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+isp_video_set_crop(struct file *file, void *fh, const struct v4l2_crop *crop)
{
struct isp_video *video = video_drvdata(file);
struct v4l2_subdev *subdev;
diff --git a/drivers/media/platform/s5p-fimc/Kconfig b/drivers/media/platform/s5p-fimc/Kconfig
index 8f090a8f270e..c16b20d86ed2 100644
--- a/drivers/media/platform/s5p-fimc/Kconfig
+++ b/drivers/media/platform/s5p-fimc/Kconfig
@@ -24,6 +24,7 @@ config VIDEO_S5P_FIMC
config VIDEO_S5P_MIPI_CSIS
tristate "S5P/EXYNOS MIPI-CSI2 receiver (MIPI-CSIS) driver"
depends on REGULATOR
+ select S5P_SETUP_MIPIPHY
help
This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC MIPI-CSI2
receiver (MIPI-CSIS) devices.
diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c
index 367efd164d0f..891ee873c62b 100644
--- a/drivers/media/platform/s5p-fimc/fimc-capture.c
+++ b/drivers/media/platform/s5p-fimc/fimc-capture.c
@@ -556,8 +556,7 @@ static int fimc_capture_close(struct file *file)
dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
- if (mutex_lock_interruptible(&fimc->lock))
- return -ERESTARTSYS;
+ mutex_lock(&fimc->lock);
if (--fimc->vid_cap.refcnt == 0) {
clear_bit(ST_CAPT_BUSY, &fimc->state);
@@ -1736,7 +1735,9 @@ static int fimc_register_capture_device(struct fimc_dev *fimc,
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct fimc_vid_buffer);
- vb2_queue_init(q);
+ ret = vb2_queue_init(q);
+ if (ret)
+ goto err_ent;
vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK;
ret = media_entity_init(&vfd->entity, 1, &vid_cap->vd_pad, 0);
@@ -1772,9 +1773,13 @@ static int fimc_capture_subdev_registered(struct v4l2_subdev *sd)
if (ret)
return ret;
+ fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd);
+
ret = fimc_register_capture_device(fimc, sd->v4l2_dev);
- if (ret)
+ if (ret) {
fimc_unregister_m2m_device(fimc);
+ fimc->pipeline_ops = NULL;
+ }
return ret;
}
@@ -1791,6 +1796,7 @@ static void fimc_capture_subdev_unregistered(struct v4l2_subdev *sd)
if (video_is_registered(&fimc->vid_cap.vfd)) {
video_unregister_device(&fimc->vid_cap.vfd);
media_entity_cleanup(&fimc->vid_cap.vfd.entity);
+ fimc->pipeline_ops = NULL;
}
kfree(fimc->vid_cap.ctx);
fimc->vid_cap.ctx = NULL;
diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c
index 70bcf39de879..1b309a72f09f 100644
--- a/drivers/media/platform/s5p-fimc/fimc-lite.c
+++ b/drivers/media/platform/s5p-fimc/fimc-lite.c
@@ -491,8 +491,7 @@ static int fimc_lite_close(struct file *file)
struct fimc_lite *fimc = video_drvdata(file);
int ret;
- if (mutex_lock_interruptible(&fimc->lock))
- return -ERESTARTSYS;
+ mutex_lock(&fimc->lock);
if (--fimc->ref_count == 0 && fimc->out_path == FIMC_IO_DMA) {
clear_bit(ST_FLITE_IN_USE, &fimc->state);
@@ -1253,7 +1252,9 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
q->buf_struct_size = sizeof(struct flite_buffer);
q->drv_priv = fimc;
- vb2_queue_init(q);
+ ret = vb2_queue_init(q);
+ if (ret < 0)
+ return ret;
fimc->vd_pad.flags = MEDIA_PAD_FL_SINK;
ret = media_entity_init(&vfd->entity, 1, &fimc->vd_pad, 0);
@@ -1261,10 +1262,12 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
return ret;
video_set_drvdata(vfd, fimc);
+ fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd);
ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
if (ret < 0) {
media_entity_cleanup(&vfd->entity);
+ fimc->pipeline_ops = NULL;
return ret;
}
@@ -1283,6 +1286,7 @@ static void fimc_lite_subdev_unregistered(struct v4l2_subdev *sd)
if (video_is_registered(&fimc->vfd)) {
video_unregister_device(&fimc->vfd);
media_entity_cleanup(&fimc->vfd.entity);
+ fimc->pipeline_ops = NULL;
}
}
diff --git a/drivers/media/platform/s5p-fimc/fimc-m2m.c b/drivers/media/platform/s5p-fimc/fimc-m2m.c
index 4500e44f6857..62afed3162ea 100644
--- a/drivers/media/platform/s5p-fimc/fimc-m2m.c
+++ b/drivers/media/platform/s5p-fimc/fimc-m2m.c
@@ -718,8 +718,7 @@ static int fimc_m2m_release(struct file *file)
dbg("pid: %d, state: 0x%lx, refcnt= %d",
task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
- if (mutex_lock_interruptible(&fimc->lock))
- return -ERESTARTSYS;
+ mutex_lock(&fimc->lock);
v4l2_m2m_ctx_release(ctx->m2m_ctx);
fimc_ctrls_delete(ctx);
diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c
index 80ada5882f62..0531ab70a94c 100644
--- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c
@@ -343,53 +343,50 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
static int fimc_register_callback(struct device *dev, void *p)
{
struct fimc_dev *fimc = dev_get_drvdata(dev);
- struct v4l2_subdev *sd = &fimc->vid_cap.subdev;
+ struct v4l2_subdev *sd;
struct fimc_md *fmd = p;
- int ret = 0;
-
- if (!fimc || !fimc->pdev)
- return 0;
+ int ret;
- if (fimc->pdev->id < 0 || fimc->pdev->id >= FIMC_MAX_DEVS)
+ if (fimc == NULL || fimc->id >= FIMC_MAX_DEVS)
return 0;
- fimc->pipeline_ops = &fimc_pipeline_ops;
- fmd->fimc[fimc->pdev->id] = fimc;
+ sd = &fimc->vid_cap.subdev;
sd->grp_id = FIMC_GROUP_ID;
+ v4l2_set_subdev_hostdata(sd, (void *)&fimc_pipeline_ops);
ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
if (ret) {
v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.%d (%d)\n",
fimc->id, ret);
+ return ret;
}
- return ret;
+ fmd->fimc[fimc->id] = fimc;
+ return 0;
}
static int fimc_lite_register_callback(struct device *dev, void *p)
{
struct fimc_lite *fimc = dev_get_drvdata(dev);
- struct v4l2_subdev *sd = &fimc->subdev;
struct fimc_md *fmd = p;
int ret;
- if (fimc == NULL)
+ if (fimc == NULL || fimc->index >= FIMC_LITE_MAX_DEVS)
return 0;
- if (fimc->index >= FIMC_LITE_MAX_DEVS)
- return 0;
-
- fimc->pipeline_ops = &fimc_pipeline_ops;
- fmd->fimc_lite[fimc->index] = fimc;
- sd->grp_id = FLITE_GROUP_ID;
+ fimc->subdev.grp_id = FLITE_GROUP_ID;
+ v4l2_set_subdev_hostdata(&fimc->subdev, (void *)&fimc_pipeline_ops);
- ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
+ ret = v4l2_device_register_subdev(&fmd->v4l2_dev, &fimc->subdev);
if (ret) {
v4l2_err(&fmd->v4l2_dev,
"Failed to register FIMC-LITE.%d (%d)\n",
fimc->index, ret);
+ return ret;
}
- return ret;
+
+ fmd->fimc_lite[fimc->index] = fimc;
+ return 0;
}
static int csis_register_callback(struct device *dev, void *p)
@@ -407,10 +404,12 @@ static int csis_register_callback(struct device *dev, void *p)
v4l2_info(sd, "csis%d sd: %s\n", pdev->id, sd->name);
id = pdev->id < 0 ? 0 : pdev->id;
- fmd->csis[id].sd = sd;
sd->grp_id = CSIS_GROUP_ID;
+
ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
- if (ret)
+ if (!ret)
+ fmd->csis[id].sd = sd;
+ else
v4l2_err(&fmd->v4l2_dev,
"Failed to register CSIS subdevice: %d\n", ret);
return ret;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index 130f4ac8649e..3afe879d54d7 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -381,11 +381,8 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
ctx->consumed_stream += s5p_mfc_hw_call(dev->mfc_ops,
get_consumed_stream, dev);
if (ctx->codec_mode != S5P_MFC_CODEC_H264_DEC &&
- s5p_mfc_hw_call(dev->mfc_ops,
- get_dec_frame_type, dev) ==
- S5P_FIMV_DECODE_FRAME_P_FRAME
- && ctx->consumed_stream + STUFF_BYTE <
- src_buf->b->v4l2_planes[0].bytesused) {
+ ctx->consumed_stream + STUFF_BYTE <
+ src_buf->b->v4l2_planes[0].bytesused) {
/* Run MFC again on the same buffer */
mfc_debug(2, "Running again the same buffer\n");
ctx->after_packed_pb = 1;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
index 50b5bee3c44e..3a8cfd9fc1bd 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
@@ -1762,7 +1762,7 @@ int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev)
int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6);
+ return mfc_read(dev, S5P_FIMV_D_DECODED_LUMA_ADDR_V6);
}
int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev)
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c
index 85fd312f0a82..a1c87f0ceaab 100644
--- a/drivers/media/platform/sh_vou.c
+++ b/drivers/media/platform/sh_vou.c
@@ -935,9 +935,10 @@ static int sh_vou_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
/* Assume a dull encoder, do all the work ourselves. */
static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a)
{
+ struct v4l2_crop a_writable = *a;
struct video_device *vdev = video_devdata(file);
struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
- struct v4l2_rect *rect = &a->c;
+ struct v4l2_rect *rect = &a_writable.c;
struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT};
struct v4l2_pix_format *pix = &vou_dev->pix;
struct sh_vou_geometry geo;
diff --git a/drivers/media/platform/soc_camera/mx1_camera.c b/drivers/media/platform/soc_camera/mx1_camera.c
index bbe70991d30b..032b8c9097f9 100644
--- a/drivers/media/platform/soc_camera/mx1_camera.c
+++ b/drivers/media/platform/soc_camera/mx1_camera.c
@@ -470,14 +470,6 @@ static void mx1_camera_remove_device(struct soc_camera_device *icd)
pcdev->icd = NULL;
}
-static int mx1_camera_set_crop(struct soc_camera_device *icd,
- struct v4l2_crop *a)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-
- return v4l2_subdev_call(sd, video, s_crop, a);
-}
-
static int mx1_camera_set_bus_param(struct soc_camera_device *icd)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
@@ -689,7 +681,6 @@ static struct soc_camera_host_ops mx1_soc_camera_host_ops = {
.add = mx1_camera_add_device,
.remove = mx1_camera_remove_device,
.set_bus_param = mx1_camera_set_bus_param,
- .set_crop = mx1_camera_set_crop,
.set_fmt = mx1_camera_set_fmt,
.try_fmt = mx1_camera_try_fmt,
.init_videobuf = mx1_camera_init_videobuf,
diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c
index 9fd9d1c5b218..9a55f4c4c7f4 100644
--- a/drivers/media/platform/soc_camera/mx2_camera.c
+++ b/drivers/media/platform/soc_camera/mx2_camera.c
@@ -864,8 +864,10 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count)
bytesperline = soc_mbus_bytes_per_line(icd->user_width,
icd->current_fmt->host_fmt);
- if (bytesperline < 0)
+ if (bytesperline < 0) {
+ spin_unlock_irqrestore(&pcdev->lock, flags);
return bytesperline;
+ }
/*
* I didn't manage to properly enable/disable the prp
@@ -878,8 +880,10 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count)
pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev,
pcdev->discard_size, &pcdev->discard_buffer_dma,
GFP_KERNEL);
- if (!pcdev->discard_buffer)
+ if (!pcdev->discard_buffer) {
+ spin_unlock_irqrestore(&pcdev->lock, flags);
return -ENOMEM;
+ }
pcdev->buf_discard[0].discard = true;
list_add_tail(&pcdev->buf_discard[0].queue,
@@ -1099,9 +1103,10 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
}
static int mx2_camera_set_crop(struct soc_camera_device *icd,
- struct v4l2_crop *a)
+ const struct v4l2_crop *a)
{
- struct v4l2_rect *rect = &a->c;
+ struct v4l2_crop a_writable = *a;
+ struct v4l2_rect *rect = &a_writable.c;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct v4l2_mbus_framefmt mf;
int ret;
diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c
index 3557ac97e430..261f6e9e1b17 100644
--- a/drivers/media/platform/soc_camera/mx3_camera.c
+++ b/drivers/media/platform/soc_camera/mx3_camera.c
@@ -799,9 +799,10 @@ static inline void stride_align(__u32 *width)
* default g_crop and cropcap from soc_camera.c
*/
static int mx3_camera_set_crop(struct soc_camera_device *icd,
- struct v4l2_crop *a)
+ const struct v4l2_crop *a)
{
- struct v4l2_rect *rect = &a->c;
+ struct v4l2_crop a_writable = *a;
+ struct v4l2_rect *rect = &a_writable.c;
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct mx3_camera_dev *mx3_cam = ici->priv;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c
index fa08c7695ccb..13636a585106 100644
--- a/drivers/media/platform/soc_camera/omap1_camera.c
+++ b/drivers/media/platform/soc_camera/omap1_camera.c
@@ -1215,9 +1215,9 @@ static int set_mbus_format(struct omap1_cam_dev *pcdev, struct device *dev,
}
static int omap1_cam_set_crop(struct soc_camera_device *icd,
- struct v4l2_crop *crop)
+ const struct v4l2_crop *crop)
{
- struct v4l2_rect *rect = &crop->c;
+ const struct v4l2_rect *rect = &crop->c;
const struct soc_camera_format_xlate *xlate = icd->current_fmt;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct device *dev = icd->parent;
diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c
index 1e3776d08dac..3434ffe79c6e 100644
--- a/drivers/media/platform/soc_camera/pxa_camera.c
+++ b/drivers/media/platform/soc_camera/pxa_camera.c
@@ -1337,9 +1337,9 @@ static int pxa_camera_check_frame(u32 width, u32 height)
}
static int pxa_camera_set_crop(struct soc_camera_device *icd,
- struct v4l2_crop *a)
+ const struct v4l2_crop *a)
{
- struct v4l2_rect *rect = &a->c;
+ const struct v4l2_rect *rect = &a->c;
struct device *dev = icd->parent;
struct soc_camera_host *ici = to_soc_camera_host(dev);
struct pxa_camera_dev *pcdev = ici->priv;
diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
index 0a24253dcda2..2d8861c0e8f2 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
@@ -1182,13 +1182,13 @@ static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd)
}
/* Check if any dimension of r1 is smaller than respective one of r2 */
-static bool is_smaller(struct v4l2_rect *r1, struct v4l2_rect *r2)
+static bool is_smaller(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
{
return r1->width < r2->width || r1->height < r2->height;
}
/* Check if r1 fails to cover r2 */
-static bool is_inside(struct v4l2_rect *r1, struct v4l2_rect *r2)
+static bool is_inside(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
{
return r1->left > r2->left || r1->top > r2->top ||
r1->left + r1->width < r2->left + r2->width ||
@@ -1263,7 +1263,7 @@ static void update_subrect(struct sh_mobile_ceu_cam *cam)
* 3. if (2) failed, try to request the maximum image
*/
static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop,
- const struct v4l2_crop *cam_crop)
+ struct v4l2_crop *cam_crop)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c;
@@ -1519,7 +1519,8 @@ static int client_scale(struct soc_camera_device *icd,
static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
const struct v4l2_crop *a)
{
- struct v4l2_rect *rect = &a->c;
+ struct v4l2_crop a_writable = *a;
+ const struct v4l2_rect *rect = &a_writable.c;
struct device *dev = icd->parent;
struct soc_camera_host *ici = to_soc_camera_host(dev);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
@@ -1545,7 +1546,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
* 1. - 2. Apply iterative camera S_CROP for new input window, read back
* actual camera rectangle.
*/
- ret = client_s_crop(icd, a, &cam_crop);
+ ret = client_s_crop(icd, &a_writable, &cam_crop);
if (ret < 0)
return ret;
@@ -1946,7 +1947,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
}
static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd,
- struct v4l2_crop *a)
+ const struct v4l2_crop *a)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index 9859d2a2449b..ba51f65204de 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -283,14 +283,13 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed,
/* activate the pid on the device pid filter */
if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER &&
- adap->pid_filtering &&
- adap->props->pid_filter)
+ adap->pid_filtering && adap->props->pid_filter) {
ret = adap->props->pid_filter(adap, dvbdmxfeed->index,
dvbdmxfeed->pid, (count == 1) ? 1 : 0);
- if (ret < 0)
- dev_err(&d->udev->dev, "%s: pid_filter() " \
- "failed=%d\n", KBUILD_MODNAME,
- ret);
+ if (ret < 0)
+ dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ }
/* start feeding if it is first pid */
if (adap->feed_count == 1 && count == 1) {
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
index 0431beed0ef4..5716662b4834 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
@@ -32,9 +32,7 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
return -EINVAL;
}
- ret = mutex_lock_interruptible(&d->usb_mutex);
- if (ret < 0)
- return ret;
+ mutex_lock(&d->usb_mutex);
dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, wlen, wbuf);
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index adabba8d28bc..093f1acce403 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -1346,6 +1346,10 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
&rtl2832u_props, "DigitalNow Quad DVB-T Receiver", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d3,
&rtl2832u_props, "TerraTec Cinergy T Stick RC (Rev. 3)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1102,
+ &rtl2832u_props, "Dexatek DK mini DVB-T Dongle", NULL) },
+ { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d7,
+ &rtl2832u_props, "TerraTec Cinergy T Stick+", NULL) },
{ }
};
MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table);
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index 1b48f2094806..f4f9bf84bc7b 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -98,9 +98,9 @@ static irqreturn_t arizona_underclocked(int irq, void *data)
if (val & ARIZONA_AIF3_UNDERCLOCKED_STS)
dev_err(arizona->dev, "AIF3 underclocked\n");
- if (val & ARIZONA_AIF3_UNDERCLOCKED_STS)
- dev_err(arizona->dev, "AIF3 underclocked\n");
if (val & ARIZONA_AIF2_UNDERCLOCKED_STS)
+ dev_err(arizona->dev, "AIF2 underclocked\n");
+ if (val & ARIZONA_AIF1_UNDERCLOCKED_STS)
dev_err(arizona->dev, "AIF1 underclocked\n");
if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS)
dev_err(arizona->dev, "ISRC2 underclocked\n");
@@ -415,11 +415,19 @@ int __devinit arizona_dev_init(struct arizona *arizona)
/* If we have a /RESET GPIO we'll already be reset */
if (!arizona->pdata.reset) {
+ regcache_mark_dirty(arizona->regmap);
+
ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0);
if (ret != 0) {
dev_err(dev, "Failed to reset device: %d\n", ret);
goto err_reset;
}
+
+ ret = regcache_sync(arizona->regmap);
+ if (ret != 0) {
+ dev_err(dev, "Failed to sync device: %d\n", ret);
+ goto err_reset;
+ }
}
ret = arizona_wait_for_boot(arizona);
@@ -520,7 +528,7 @@ int __devinit arizona_dev_init(struct arizona *arizona)
break;
case WM5110:
ret = mfd_add_devices(arizona->dev, -1, wm5110_devs,
- ARRAY_SIZE(wm5102_devs), NULL, 0, NULL);
+ ARRAY_SIZE(wm5110_devs), NULL, 0, NULL);
break;
}
diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c
index ef0f2d001df2..b1b009177405 100644
--- a/drivers/mfd/arizona-irq.c
+++ b/drivers/mfd/arizona-irq.c
@@ -178,6 +178,7 @@ int arizona_irq_init(struct arizona *arizona)
switch (arizona->rev) {
case 0:
+ case 1:
ctrlif_error = false;
break;
default:
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 00b8b0f3dfb6..b96661d453aa 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -31,6 +31,7 @@
#include <linux/mfd/abx500/ab8500.h>
#include <linux/regulator/db8500-prcmu.h>
#include <linux/regulator/machine.h>
+#include <linux/cpufreq.h>
#include <asm/hardware/gic.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
@@ -420,9 +421,6 @@ static struct {
static atomic_t ac_wake_req_state = ATOMIC_INIT(0);
-/* Functions definition */
-static void compute_armss_rate(void);
-
/* Spinlocks */
static DEFINE_SPINLOCK(prcmu_lock);
static DEFINE_SPINLOCK(clkout_lock);
@@ -1019,7 +1017,6 @@ int db8500_prcmu_set_arm_opp(u8 opp)
(mb1_transfer.ack.arm_opp != opp))
r = -EIO;
- compute_armss_rate();
mutex_unlock(&mb1_transfer.lock);
return r;
@@ -1169,12 +1166,12 @@ int db8500_prcmu_get_ape_opp(void)
}
/**
- * prcmu_request_ape_opp_100_voltage - Request APE OPP 100% voltage
+ * db8500_prcmu_request_ape_opp_100_voltage - Request APE OPP 100% voltage
* @enable: true to request the higher voltage, false to drop a request.
*
* Calls to this function to enable and disable requests must be balanced.
*/
-int prcmu_request_ape_opp_100_voltage(bool enable)
+int db8500_prcmu_request_ape_opp_100_voltage(bool enable)
{
int r = 0;
u8 header;
@@ -1669,13 +1666,8 @@ static unsigned long clock_rate(u8 clock)
else
return 0;
}
-static unsigned long latest_armss_rate;
-static unsigned long armss_rate(void)
-{
- return latest_armss_rate;
-}
-static void compute_armss_rate(void)
+static unsigned long armss_rate(void)
{
u32 r;
unsigned long rate;
@@ -1700,7 +1692,7 @@ static void compute_armss_rate(void)
rate = pll_rate(PRCM_PLLARM_FREQ, ROOT_CLOCK_RATE, PLL_DIV);
}
- latest_armss_rate = rate;
+ return rate;
}
static unsigned long dsiclk_rate(u8 n)
@@ -1820,6 +1812,35 @@ static long round_clock_rate(u8 clock, unsigned long rate)
return rounded_rate;
}
+/* CPU FREQ table, may be changed due to if MAX_OPP is supported. */
+static struct cpufreq_frequency_table db8500_cpufreq_table[] = {
+ { .frequency = 200000, .index = ARM_EXTCLK,},
+ { .frequency = 400000, .index = ARM_50_OPP,},
+ { .frequency = 800000, .index = ARM_100_OPP,},
+ { .frequency = CPUFREQ_TABLE_END,}, /* To be used for MAX_OPP. */
+ { .frequency = CPUFREQ_TABLE_END,},
+};
+
+static long round_armss_rate(unsigned long rate)
+{
+ long freq = 0;
+ int i = 0;
+
+ /* cpufreq table frequencies is in KHz. */
+ rate = rate / 1000;
+
+ /* Find the corresponding arm opp from the cpufreq table. */
+ while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) {
+ freq = db8500_cpufreq_table[i].frequency;
+ if (freq == rate)
+ break;
+ i++;
+ }
+
+ /* Return the last valid value, even if a match was not found. */
+ return freq * 1000;
+}
+
#define MIN_PLL_VCO_RATE 600000000ULL
#define MAX_PLL_VCO_RATE 1680640000ULL
@@ -1891,6 +1912,8 @@ long prcmu_round_clock_rate(u8 clock, unsigned long rate)
{
if (clock < PRCMU_NUM_REG_CLOCKS)
return round_clock_rate(clock, rate);
+ else if (clock == PRCMU_ARMSS)
+ return round_armss_rate(rate);
else if (clock == PRCMU_PLLDSI)
return round_plldsi_rate(rate);
else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
@@ -1950,6 +1973,27 @@ static void set_clock_rate(u8 clock, unsigned long rate)
spin_unlock_irqrestore(&clk_mgt_lock, flags);
}
+static int set_armss_rate(unsigned long rate)
+{
+ int i = 0;
+
+ /* cpufreq table frequencies is in KHz. */
+ rate = rate / 1000;
+
+ /* Find the corresponding arm opp from the cpufreq table. */
+ while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) {
+ if (db8500_cpufreq_table[i].frequency == rate)
+ break;
+ i++;
+ }
+
+ if (db8500_cpufreq_table[i].frequency != rate)
+ return -EINVAL;
+
+ /* Set the new arm opp. */
+ return db8500_prcmu_set_arm_opp(db8500_cpufreq_table[i].index);
+}
+
static int set_plldsi_rate(unsigned long rate)
{
unsigned long src_rate;
@@ -2030,6 +2074,8 @@ int prcmu_set_clock_rate(u8 clock, unsigned long rate)
{
if (clock < PRCMU_NUM_REG_CLOCKS)
set_clock_rate(clock, rate);
+ else if (clock == PRCMU_ARMSS)
+ return set_armss_rate(rate);
else if (clock == PRCMU_PLLDSI)
return set_plldsi_rate(rate);
else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
@@ -2754,8 +2800,6 @@ void __init db8500_prcmu_early_init(void)
init_completion(&mb5_transfer.work);
INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work);
-
- compute_armss_rate();
}
static void __init init_prcm_registers(void)
@@ -3020,6 +3064,8 @@ static struct mfd_cell db8500_prcmu_devs[] = {
{
.name = "cpufreq-u8500",
.of_compatible = "stericsson,cpufreq-u8500",
+ .platform_data = &db8500_cpufreq_table,
+ .pdata_size = sizeof(db8500_cpufreq_table),
},
{
.name = "ab8500-core",
@@ -3030,6 +3076,14 @@ static struct mfd_cell db8500_prcmu_devs[] = {
},
};
+static void db8500_prcmu_update_cpufreq(void)
+{
+ if (prcmu_has_arm_maxopp()) {
+ db8500_cpufreq_table[3].frequency = 1000000;
+ db8500_cpufreq_table[3].index = ARM_MAX_OPP;
+ }
+}
+
/**
* prcmu_fw_init - arch init call for the Linux PRCMU fw init logic
*
@@ -3074,6 +3128,8 @@ static int __devinit db8500_prcmu_probe(struct platform_device *pdev)
if (cpu_is_u8500v20_or_later())
prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
+ db8500_prcmu_update_cpufreq();
+
err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs,
ARRAY_SIZE(db8500_prcmu_devs), NULL, 0, NULL);
if (err) {
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 4ae642320205..a071a8643a47 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -671,7 +671,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
}
if (IS_ENABLED(CONFIG_PWM_TWL6030) && twl_class_is_6030()) {
- child = add_child(TWL6030_MODULE_ID1, "twl6030-pwm", NULL, 0,
+ child = add_child(SUB_CHIP_ID1, "twl6030-pwm", NULL, 0,
false, 0, 0);
if (IS_ERR(child))
return PTR_ERR(child);
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index ad733d76207a..cdd1173ed4e9 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -672,7 +672,8 @@ int twl4030_sih_setup(struct device *dev, int module, int irq_base)
irq = sih_mod + twl4030_irq_base;
irq_set_handler_data(irq, agent);
agent->irq_name = kasprintf(GFP_KERNEL, "twl4030_%s", sih->name);
- status = request_threaded_irq(irq, NULL, handle_twl4030_sih, 0,
+ status = request_threaded_irq(irq, NULL, handle_twl4030_sih,
+ IRQF_EARLY_RESUME,
agent->irq_name ?: sih->name, NULL);
dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", sih->name,
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c
index 01b9255ed631..14490cc785d2 100644
--- a/drivers/mfd/wm5102-tables.c
+++ b/drivers/mfd/wm5102-tables.c
@@ -43,6 +43,7 @@ static const struct reg_default wm5102_reva_patch[] = {
{ 0x479, 0x0A30 },
{ 0x47B, 0x0810 },
{ 0x47D, 0x0510 },
+ { 0x4D1, 0x017F },
{ 0x500, 0x000D },
{ 0x507, 0x1820 },
{ 0x508, 0x1820 },
@@ -52,524 +53,6 @@ static const struct reg_default wm5102_reva_patch[] = {
{ 0x580, 0x000D },
{ 0x587, 0x1820 },
{ 0x588, 0x1820 },
- { 0x101, 0x8140 },
- { 0x3000, 0x2225 },
- { 0x3001, 0x3a03 },
- { 0x3002, 0x0225 },
- { 0x3003, 0x0801 },
- { 0x3004, 0x6249 },
- { 0x3005, 0x0c04 },
- { 0x3006, 0x0225 },
- { 0x3007, 0x5901 },
- { 0x3008, 0xe249 },
- { 0x3009, 0x030d },
- { 0x300a, 0x0249 },
- { 0x300b, 0x2c01 },
- { 0x300c, 0xe249 },
- { 0x300d, 0x4342 },
- { 0x300e, 0xe249 },
- { 0x300f, 0x73c0 },
- { 0x3010, 0x4249 },
- { 0x3011, 0x0c00 },
- { 0x3012, 0x0225 },
- { 0x3013, 0x1f01 },
- { 0x3014, 0x0225 },
- { 0x3015, 0x1e01 },
- { 0x3016, 0x0225 },
- { 0x3017, 0xfa00 },
- { 0x3018, 0x0000 },
- { 0x3019, 0xf000 },
- { 0x301a, 0x0000 },
- { 0x301b, 0xf000 },
- { 0x301c, 0x0000 },
- { 0x301d, 0xf000 },
- { 0x301e, 0x0000 },
- { 0x301f, 0xf000 },
- { 0x3020, 0x0000 },
- { 0x3021, 0xf000 },
- { 0x3022, 0x0000 },
- { 0x3023, 0xf000 },
- { 0x3024, 0x0000 },
- { 0x3025, 0xf000 },
- { 0x3026, 0x0000 },
- { 0x3027, 0xf000 },
- { 0x3028, 0x0000 },
- { 0x3029, 0xf000 },
- { 0x302a, 0x0000 },
- { 0x302b, 0xf000 },
- { 0x302c, 0x0000 },
- { 0x302d, 0xf000 },
- { 0x302e, 0x0000 },
- { 0x302f, 0xf000 },
- { 0x3030, 0x0225 },
- { 0x3031, 0x1a01 },
- { 0x3032, 0x0225 },
- { 0x3033, 0x1e00 },
- { 0x3034, 0x0225 },
- { 0x3035, 0x1f00 },
- { 0x3036, 0x6225 },
- { 0x3037, 0xf800 },
- { 0x3038, 0x0000 },
- { 0x3039, 0xf000 },
- { 0x303a, 0x0000 },
- { 0x303b, 0xf000 },
- { 0x303c, 0x0000 },
- { 0x303d, 0xf000 },
- { 0x303e, 0x0000 },
- { 0x303f, 0xf000 },
- { 0x3040, 0x2226 },
- { 0x3041, 0x3a03 },
- { 0x3042, 0x0226 },
- { 0x3043, 0x0801 },
- { 0x3044, 0x6249 },
- { 0x3045, 0x0c06 },
- { 0x3046, 0x0226 },
- { 0x3047, 0x5901 },
- { 0x3048, 0xe249 },
- { 0x3049, 0x030d },
- { 0x304a, 0x0249 },
- { 0x304b, 0x2c01 },
- { 0x304c, 0xe249 },
- { 0x304d, 0x4342 },
- { 0x304e, 0xe249 },
- { 0x304f, 0x73c0 },
- { 0x3050, 0x4249 },
- { 0x3051, 0x0c00 },
- { 0x3052, 0x0226 },
- { 0x3053, 0x1f01 },
- { 0x3054, 0x0226 },
- { 0x3055, 0x1e01 },
- { 0x3056, 0x0226 },
- { 0x3057, 0xfa00 },
- { 0x3058, 0x0000 },
- { 0x3059, 0xf000 },
- { 0x305a, 0x0000 },
- { 0x305b, 0xf000 },
- { 0x305c, 0x0000 },
- { 0x305d, 0xf000 },
- { 0x305e, 0x0000 },
- { 0x305f, 0xf000 },
- { 0x3060, 0x0000 },
- { 0x3061, 0xf000 },
- { 0x3062, 0x0000 },
- { 0x3063, 0xf000 },
- { 0x3064, 0x0000 },
- { 0x3065, 0xf000 },
- { 0x3066, 0x0000 },
- { 0x3067, 0xf000 },
- { 0x3068, 0x0000 },
- { 0x3069, 0xf000 },
- { 0x306a, 0x0000 },
- { 0x306b, 0xf000 },
- { 0x306c, 0x0000 },
- { 0x306d, 0xf000 },
- { 0x306e, 0x0000 },
- { 0x306f, 0xf000 },
- { 0x3070, 0x0226 },
- { 0x3071, 0x1a01 },
- { 0x3072, 0x0226 },
- { 0x3073, 0x1e00 },
- { 0x3074, 0x0226 },
- { 0x3075, 0x1f00 },
- { 0x3076, 0x6226 },
- { 0x3077, 0xf800 },
- { 0x3078, 0x0000 },
- { 0x3079, 0xf000 },
- { 0x307a, 0x0000 },
- { 0x307b, 0xf000 },
- { 0x307c, 0x0000 },
- { 0x307d, 0xf000 },
- { 0x307e, 0x0000 },
- { 0x307f, 0xf000 },
- { 0x3080, 0x2227 },
- { 0x3081, 0x3a03 },
- { 0x3082, 0x0227 },
- { 0x3083, 0x0801 },
- { 0x3084, 0x6255 },
- { 0x3085, 0x0c04 },
- { 0x3086, 0x0227 },
- { 0x3087, 0x5901 },
- { 0x3088, 0xe255 },
- { 0x3089, 0x030d },
- { 0x308a, 0x0255 },
- { 0x308b, 0x2c01 },
- { 0x308c, 0xe255 },
- { 0x308d, 0x4342 },
- { 0x308e, 0xe255 },
- { 0x308f, 0x73c0 },
- { 0x3090, 0x4255 },
- { 0x3091, 0x0c00 },
- { 0x3092, 0x0227 },
- { 0x3093, 0x1f01 },
- { 0x3094, 0x0227 },
- { 0x3095, 0x1e01 },
- { 0x3096, 0x0227 },
- { 0x3097, 0xfa00 },
- { 0x3098, 0x0000 },
- { 0x3099, 0xf000 },
- { 0x309a, 0x0000 },
- { 0x309b, 0xf000 },
- { 0x309c, 0x0000 },
- { 0x309d, 0xf000 },
- { 0x309e, 0x0000 },
- { 0x309f, 0xf000 },
- { 0x30a0, 0x0000 },
- { 0x30a1, 0xf000 },
- { 0x30a2, 0x0000 },
- { 0x30a3, 0xf000 },
- { 0x30a4, 0x0000 },
- { 0x30a5, 0xf000 },
- { 0x30a6, 0x0000 },
- { 0x30a7, 0xf000 },
- { 0x30a8, 0x0000 },
- { 0x30a9, 0xf000 },
- { 0x30aa, 0x0000 },
- { 0x30ab, 0xf000 },
- { 0x30ac, 0x0000 },
- { 0x30ad, 0xf000 },
- { 0x30ae, 0x0000 },
- { 0x30af, 0xf000 },
- { 0x30b0, 0x0227 },
- { 0x30b1, 0x1a01 },
- { 0x30b2, 0x0227 },
- { 0x30b3, 0x1e00 },
- { 0x30b4, 0x0227 },
- { 0x30b5, 0x1f00 },
- { 0x30b6, 0x6227 },
- { 0x30b7, 0xf800 },
- { 0x30b8, 0x0000 },
- { 0x30b9, 0xf000 },
- { 0x30ba, 0x0000 },
- { 0x30bb, 0xf000 },
- { 0x30bc, 0x0000 },
- { 0x30bd, 0xf000 },
- { 0x30be, 0x0000 },
- { 0x30bf, 0xf000 },
- { 0x30c0, 0x2228 },
- { 0x30c1, 0x3a03 },
- { 0x30c2, 0x0228 },
- { 0x30c3, 0x0801 },
- { 0x30c4, 0x6255 },
- { 0x30c5, 0x0c06 },
- { 0x30c6, 0x0228 },
- { 0x30c7, 0x5901 },
- { 0x30c8, 0xe255 },
- { 0x30c9, 0x030d },
- { 0x30ca, 0x0255 },
- { 0x30cb, 0x2c01 },
- { 0x30cc, 0xe255 },
- { 0x30cd, 0x4342 },
- { 0x30ce, 0xe255 },
- { 0x30cf, 0x73c0 },
- { 0x30d0, 0x4255 },
- { 0x30d1, 0x0c00 },
- { 0x30d2, 0x0228 },
- { 0x30d3, 0x1f01 },
- { 0x30d4, 0x0228 },
- { 0x30d5, 0x1e01 },
- { 0x30d6, 0x0228 },
- { 0x30d7, 0xfa00 },
- { 0x30d8, 0x0000 },
- { 0x30d9, 0xf000 },
- { 0x30da, 0x0000 },
- { 0x30db, 0xf000 },
- { 0x30dc, 0x0000 },
- { 0x30dd, 0xf000 },
- { 0x30de, 0x0000 },
- { 0x30df, 0xf000 },
- { 0x30e0, 0x0000 },
- { 0x30e1, 0xf000 },
- { 0x30e2, 0x0000 },
- { 0x30e3, 0xf000 },
- { 0x30e4, 0x0000 },
- { 0x30e5, 0xf000 },
- { 0x30e6, 0x0000 },
- { 0x30e7, 0xf000 },
- { 0x30e8, 0x0000 },
- { 0x30e9, 0xf000 },
- { 0x30ea, 0x0000 },
- { 0x30eb, 0xf000 },
- { 0x30ec, 0x0000 },
- { 0x30ed, 0xf000 },
- { 0x30ee, 0x0000 },
- { 0x30ef, 0xf000 },
- { 0x30f0, 0x0228 },
- { 0x30f1, 0x1a01 },
- { 0x30f2, 0x0228 },
- { 0x30f3, 0x1e00 },
- { 0x30f4, 0x0228 },
- { 0x30f5, 0x1f00 },
- { 0x30f6, 0x6228 },
- { 0x30f7, 0xf800 },
- { 0x30f8, 0x0000 },
- { 0x30f9, 0xf000 },
- { 0x30fa, 0x0000 },
- { 0x30fb, 0xf000 },
- { 0x30fc, 0x0000 },
- { 0x30fd, 0xf000 },
- { 0x30fe, 0x0000 },
- { 0x30ff, 0xf000 },
- { 0x3100, 0x222b },
- { 0x3101, 0x3a03 },
- { 0x3102, 0x222b },
- { 0x3103, 0x5803 },
- { 0x3104, 0xe26f },
- { 0x3105, 0x030d },
- { 0x3106, 0x626f },
- { 0x3107, 0x2c01 },
- { 0x3108, 0xe26f },
- { 0x3109, 0x4342 },
- { 0x310a, 0xe26f },
- { 0x310b, 0x73c0 },
- { 0x310c, 0x026f },
- { 0x310d, 0x0c00 },
- { 0x310e, 0x022b },
- { 0x310f, 0x1f01 },
- { 0x3110, 0x022b },
- { 0x3111, 0x1e01 },
- { 0x3112, 0x022b },
- { 0x3113, 0xfa00 },
- { 0x3114, 0x0000 },
- { 0x3115, 0xf000 },
- { 0x3116, 0x0000 },
- { 0x3117, 0xf000 },
- { 0x3118, 0x0000 },
- { 0x3119, 0xf000 },
- { 0x311a, 0x0000 },
- { 0x311b, 0xf000 },
- { 0x311c, 0x0000 },
- { 0x311d, 0xf000 },
- { 0x311e, 0x0000 },
- { 0x311f, 0xf000 },
- { 0x3120, 0x022b },
- { 0x3121, 0x0a01 },
- { 0x3122, 0x022b },
- { 0x3123, 0x1e00 },
- { 0x3124, 0x022b },
- { 0x3125, 0x1f00 },
- { 0x3126, 0x622b },
- { 0x3127, 0xf800 },
- { 0x3128, 0x0000 },
- { 0x3129, 0xf000 },
- { 0x312a, 0x0000 },
- { 0x312b, 0xf000 },
- { 0x312c, 0x0000 },
- { 0x312d, 0xf000 },
- { 0x312e, 0x0000 },
- { 0x312f, 0xf000 },
- { 0x3130, 0x0000 },
- { 0x3131, 0xf000 },
- { 0x3132, 0x0000 },
- { 0x3133, 0xf000 },
- { 0x3134, 0x0000 },
- { 0x3135, 0xf000 },
- { 0x3136, 0x0000 },
- { 0x3137, 0xf000 },
- { 0x3138, 0x0000 },
- { 0x3139, 0xf000 },
- { 0x313a, 0x0000 },
- { 0x313b, 0xf000 },
- { 0x313c, 0x0000 },
- { 0x313d, 0xf000 },
- { 0x313e, 0x0000 },
- { 0x313f, 0xf000 },
- { 0x3140, 0x0000 },
- { 0x3141, 0xf000 },
- { 0x3142, 0x0000 },
- { 0x3143, 0xf000 },
- { 0x3144, 0x0000 },
- { 0x3145, 0xf000 },
- { 0x3146, 0x0000 },
- { 0x3147, 0xf000 },
- { 0x3148, 0x0000 },
- { 0x3149, 0xf000 },
- { 0x314a, 0x0000 },
- { 0x314b, 0xf000 },
- { 0x314c, 0x0000 },
- { 0x314d, 0xf000 },
- { 0x314e, 0x0000 },
- { 0x314f, 0xf000 },
- { 0x3150, 0x0000 },
- { 0x3151, 0xf000 },
- { 0x3152, 0x0000 },
- { 0x3153, 0xf000 },
- { 0x3154, 0x0000 },
- { 0x3155, 0xf000 },
- { 0x3156, 0x0000 },
- { 0x3157, 0xf000 },
- { 0x3158, 0x0000 },
- { 0x3159, 0xf000 },
- { 0x315a, 0x0000 },
- { 0x315b, 0xf000 },
- { 0x315c, 0x0000 },
- { 0x315d, 0xf000 },
- { 0x315e, 0x0000 },
- { 0x315f, 0xf000 },
- { 0x3160, 0x0000 },
- { 0x3161, 0xf000 },
- { 0x3162, 0x0000 },
- { 0x3163, 0xf000 },
- { 0x3164, 0x0000 },
- { 0x3165, 0xf000 },
- { 0x3166, 0x0000 },
- { 0x3167, 0xf000 },
- { 0x3168, 0x0000 },
- { 0x3169, 0xf000 },
- { 0x316a, 0x0000 },
- { 0x316b, 0xf000 },
- { 0x316c, 0x0000 },
- { 0x316d, 0xf000 },
- { 0x316e, 0x0000 },
- { 0x316f, 0xf000 },
- { 0x3170, 0x0000 },
- { 0x3171, 0xf000 },
- { 0x3172, 0x0000 },
- { 0x3173, 0xf000 },
- { 0x3174, 0x0000 },
- { 0x3175, 0xf000 },
- { 0x3176, 0x0000 },
- { 0x3177, 0xf000 },
- { 0x3178, 0x0000 },
- { 0x3179, 0xf000 },
- { 0x317a, 0x0000 },
- { 0x317b, 0xf000 },
- { 0x317c, 0x0000 },
- { 0x317d, 0xf000 },
- { 0x317e, 0x0000 },
- { 0x317f, 0xf000 },
- { 0x3180, 0x2001 },
- { 0x3181, 0xf101 },
- { 0x3182, 0x0000 },
- { 0x3183, 0xf000 },
- { 0x3184, 0x0000 },
- { 0x3185, 0xf000 },
- { 0x3186, 0x0000 },
- { 0x3187, 0xf000 },
- { 0x3188, 0x0000 },
- { 0x3189, 0xf000 },
- { 0x318a, 0x0000 },
- { 0x318b, 0xf000 },
- { 0x318c, 0x0000 },
- { 0x318d, 0xf000 },
- { 0x318e, 0x0000 },
- { 0x318f, 0xf000 },
- { 0x3190, 0x0000 },
- { 0x3191, 0xf000 },
- { 0x3192, 0x0000 },
- { 0x3193, 0xf000 },
- { 0x3194, 0x0000 },
- { 0x3195, 0xf000 },
- { 0x3196, 0x0000 },
- { 0x3197, 0xf000 },
- { 0x3198, 0x0000 },
- { 0x3199, 0xf000 },
- { 0x319a, 0x0000 },
- { 0x319b, 0xf000 },
- { 0x319c, 0x0000 },
- { 0x319d, 0xf000 },
- { 0x319e, 0x0000 },
- { 0x319f, 0xf000 },
- { 0x31a0, 0x0000 },
- { 0x31a1, 0xf000 },
- { 0x31a2, 0x0000 },
- { 0x31a3, 0xf000 },
- { 0x31a4, 0x0000 },
- { 0x31a5, 0xf000 },
- { 0x31a6, 0x0000 },
- { 0x31a7, 0xf000 },
- { 0x31a8, 0x0000 },
- { 0x31a9, 0xf000 },
- { 0x31aa, 0x0000 },
- { 0x31ab, 0xf000 },
- { 0x31ac, 0x0000 },
- { 0x31ad, 0xf000 },
- { 0x31ae, 0x0000 },
- { 0x31af, 0xf000 },
- { 0x31b0, 0x0000 },
- { 0x31b1, 0xf000 },
- { 0x31b2, 0x0000 },
- { 0x31b3, 0xf000 },
- { 0x31b4, 0x0000 },
- { 0x31b5, 0xf000 },
- { 0x31b6, 0x0000 },
- { 0x31b7, 0xf000 },
- { 0x31b8, 0x0000 },
- { 0x31b9, 0xf000 },
- { 0x31ba, 0x0000 },
- { 0x31bb, 0xf000 },
- { 0x31bc, 0x0000 },
- { 0x31bd, 0xf000 },
- { 0x31be, 0x0000 },
- { 0x31bf, 0xf000 },
- { 0x31c0, 0x0000 },
- { 0x31c1, 0xf000 },
- { 0x31c2, 0x0000 },
- { 0x31c3, 0xf000 },
- { 0x31c4, 0x0000 },
- { 0x31c5, 0xf000 },
- { 0x31c6, 0x0000 },
- { 0x31c7, 0xf000 },
- { 0x31c8, 0x0000 },
- { 0x31c9, 0xf000 },
- { 0x31ca, 0x0000 },
- { 0x31cb, 0xf000 },
- { 0x31cc, 0x0000 },
- { 0x31cd, 0xf000 },
- { 0x31ce, 0x0000 },
- { 0x31cf, 0xf000 },
- { 0x31d0, 0x0000 },
- { 0x31d1, 0xf000 },
- { 0x31d2, 0x0000 },
- { 0x31d3, 0xf000 },
- { 0x31d4, 0x0000 },
- { 0x31d5, 0xf000 },
- { 0x31d6, 0x0000 },
- { 0x31d7, 0xf000 },
- { 0x31d8, 0x0000 },
- { 0x31d9, 0xf000 },
- { 0x31da, 0x0000 },
- { 0x31db, 0xf000 },
- { 0x31dc, 0x0000 },
- { 0x31dd, 0xf000 },
- { 0x31de, 0x0000 },
- { 0x31df, 0xf000 },
- { 0x31e0, 0x0000 },
- { 0x31e1, 0xf000 },
- { 0x31e2, 0x0000 },
- { 0x31e3, 0xf000 },
- { 0x31e4, 0x0000 },
- { 0x31e5, 0xf000 },
- { 0x31e6, 0x0000 },
- { 0x31e7, 0xf000 },
- { 0x31e8, 0x0000 },
- { 0x31e9, 0xf000 },
- { 0x31ea, 0x0000 },
- { 0x31eb, 0xf000 },
- { 0x31ec, 0x0000 },
- { 0x31ed, 0xf000 },
- { 0x31ee, 0x0000 },
- { 0x31ef, 0xf000 },
- { 0x31f0, 0x0000 },
- { 0x31f1, 0xf000 },
- { 0x31f2, 0x0000 },
- { 0x31f3, 0xf000 },
- { 0x31f4, 0x0000 },
- { 0x31f5, 0xf000 },
- { 0x31f6, 0x0000 },
- { 0x31f7, 0xf000 },
- { 0x31f8, 0x0000 },
- { 0x31f9, 0xf000 },
- { 0x31fa, 0x0000 },
- { 0x31fb, 0xf000 },
- { 0x31fc, 0x0000 },
- { 0x31fd, 0xf000 },
- { 0x31fe, 0x0000 },
- { 0x31ff, 0xf000 },
- { 0x024d, 0xff50 },
- { 0x0252, 0xff50 },
- { 0x0259, 0x0112 },
- { 0x025e, 0x0112 },
- { 0x101, 0x0304 },
{ 0x80, 0x0000 },
};
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 172a768036d8..21056b9ef0a0 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -57,6 +57,7 @@ MODULE_ALIAS("mmc:block");
#define INAND_CMD38_ARG_SECERASE 0x80
#define INAND_CMD38_ARG_SECTRIM1 0x81
#define INAND_CMD38_ARG_SECTRIM2 0x88
+#define MMC_BLK_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
static DEFINE_MUTEX(block_mutex);
@@ -126,6 +127,10 @@ enum mmc_blk_status {
module_param(perdev_minors, int, 0444);
MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
+static inline int mmc_blk_part_switch(struct mmc_card *card,
+ struct mmc_blk_data *md);
+static int get_card_status(struct mmc_card *card, u32 *status, int retries);
+
static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
{
struct mmc_blk_data *md;
@@ -357,6 +362,38 @@ out:
return ERR_PTR(err);
}
+static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status,
+ u32 retries_max)
+{
+ int err;
+ u32 retry_count = 0;
+
+ if (!status || !retries_max)
+ return -EINVAL;
+
+ do {
+ err = get_card_status(card, status, 5);
+ if (err)
+ break;
+
+ if (!R1_STATUS(*status) &&
+ (R1_CURRENT_STATE(*status) != R1_STATE_PRG))
+ break; /* RPMB programming operation complete */
+
+ /*
+ * Rechedule to give the MMC device a chance to continue
+ * processing the previous command without being polled too
+ * frequently.
+ */
+ usleep_range(1000, 5000);
+ } while (++retry_count < retries_max);
+
+ if (retry_count == retries_max)
+ err = -EPERM;
+
+ return err;
+}
+
static int mmc_blk_ioctl_cmd(struct block_device *bdev,
struct mmc_ioc_cmd __user *ic_ptr)
{
@@ -368,6 +405,8 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
struct mmc_request mrq = {NULL};
struct scatterlist sg;
int err;
+ int is_rpmb = false;
+ u32 status = 0;
/*
* The caller must have CAP_SYS_RAWIO, and must be calling this on the
@@ -387,6 +426,9 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
goto cmd_err;
}
+ if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
+ is_rpmb = true;
+
card = md->queue.card;
if (IS_ERR(card)) {
err = PTR_ERR(card);
@@ -437,12 +479,23 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
mmc_claim_host(card->host);
+ err = mmc_blk_part_switch(card, md);
+ if (err)
+ goto cmd_rel_host;
+
if (idata->ic.is_acmd) {
err = mmc_app_cmd(card->host, card);
if (err)
goto cmd_rel_host;
}
+ if (is_rpmb) {
+ err = mmc_set_blockcount(card, data.blocks,
+ idata->ic.write_flag & (1 << 31));
+ if (err)
+ goto cmd_rel_host;
+ }
+
mmc_wait_for_req(card->host, &mrq);
if (cmd.error) {
@@ -478,6 +531,18 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
}
}
+ if (is_rpmb) {
+ /*
+ * Ensure RPMB command has completed by polling CMD13
+ * "Send Status".
+ */
+ err = ioctl_rpmb_card_status_poll(card, &status, 5);
+ if (err)
+ dev_err(mmc_dev(card->host),
+ "%s: Card Status=0x%08X, error %d\n",
+ __func__, status, err);
+ }
+
cmd_rel_host:
mmc_release_host(card->host);
@@ -1034,6 +1099,9 @@ static int mmc_blk_err_check(struct mmc_card *card,
*/
if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
u32 status;
+ unsigned long timeout;
+
+ timeout = jiffies + msecs_to_jiffies(MMC_BLK_TIMEOUT_MS);
do {
int err = get_card_status(card, &status, 5);
if (err) {
@@ -1041,6 +1109,17 @@ static int mmc_blk_err_check(struct mmc_card *card,
req->rq_disk->disk_name, err);
return MMC_BLK_CMD_ERR;
}
+
+ /* Timeout if the device never becomes ready for data
+ * and never leaves the program state.
+ */
+ if (time_after(jiffies, timeout)) {
+ pr_err("%s: Card stuck in programming state!"\
+ " %s %s\n", mmc_hostname(card->host),
+ req->rq_disk->disk_name, __func__);
+
+ return MMC_BLK_CMD_ERR;
+ }
/*
* Some cards mishandle the status bits,
* so make sure to check both the busy
@@ -1504,6 +1583,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
md->disk->queue = md->queue.queue;
md->disk->driverfs_dev = parent;
set_disk_ro(md->disk, md->read_only || default_ro);
+ if (area_type & MMC_BLK_DATA_AREA_RPMB)
+ md->disk->flags |= GENHD_FL_NO_PART_SCAN;
/*
* As discussed on lkml, GENHD_FL_REMOVABLE should:
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index e360a979857d..fadf52eb5d70 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -68,6 +68,16 @@ static int mmc_queue_thread(void *d)
if (req || mq->mqrq_prev->req) {
set_current_state(TASK_RUNNING);
mq->issue_fn(mq, req);
+
+ /*
+ * Current request becomes previous request
+ * and vice versa.
+ */
+ mq->mqrq_prev->brq.mrq.data = NULL;
+ mq->mqrq_prev->req = NULL;
+ tmp = mq->mqrq_prev;
+ mq->mqrq_prev = mq->mqrq_cur;
+ mq->mqrq_cur = tmp;
} else {
if (kthread_should_stop()) {
set_current_state(TASK_RUNNING);
@@ -77,13 +87,6 @@ static int mmc_queue_thread(void *d)
schedule();
down(&mq->thread_sem);
}
-
- /* Current request becomes previous request and vice versa. */
- mq->mqrq_prev->brq.mrq.data = NULL;
- mq->mqrq_prev->req = NULL;
- tmp = mq->mqrq_prev;
- mq->mqrq_prev = mq->mqrq_cur;
- mq->mqrq_cur = tmp;
} while (1);
up(&mq->thread_sem);
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 9b68933f27e7..420cb6753c1e 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -225,8 +225,7 @@ static void mmc_release_card(struct device *dev)
sdio_free_common_cis(card);
- if (card->info)
- kfree(card->info);
+ kfree(card->info);
kfree(card);
}
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 06c42cfb7c34..aaed7687cf09 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -42,6 +42,9 @@
#include "sd_ops.h"
#include "sdio_ops.h"
+/* If the device is not responding */
+#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
+
/*
* Background operations can take a long time, depending on the housekeeping
* operations the card has to perform.
@@ -1631,6 +1634,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
{
struct mmc_command cmd = {0};
unsigned int qty = 0;
+ unsigned long timeout;
int err;
/*
@@ -1708,6 +1712,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
if (mmc_host_is_spi(card->host))
goto out;
+ timeout = jiffies + msecs_to_jiffies(MMC_CORE_TIMEOUT_MS);
do {
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SEND_STATUS;
@@ -1721,8 +1726,19 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
err = -EIO;
goto out;
}
+
+ /* Timeout if the device never becomes ready for data and
+ * never leaves the program state.
+ */
+ if (time_after(jiffies, timeout)) {
+ pr_err("%s: Card stuck in programming state! %s\n",
+ mmc_hostname(card->host), __func__);
+ err = -EIO;
+ goto out;
+ }
+
} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
- R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG);
+ (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG));
out:
return err;
}
@@ -1942,6 +1958,20 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
}
EXPORT_SYMBOL(mmc_set_blocklen);
+int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
+ bool is_rel_write)
+{
+ struct mmc_command cmd = {0};
+
+ cmd.opcode = MMC_SET_BLOCK_COUNT;
+ cmd.arg = blockcount & 0x0000FFFF;
+ if (is_rel_write)
+ cmd.arg |= 1 << 31;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+ return mmc_wait_for_cmd(card->host, &cmd, 5);
+}
+EXPORT_SYMBOL(mmc_set_blockcount);
+
static void mmc_hw_reset_for_init(struct mmc_host *host)
{
if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index d96c643dde1c..35c2f85b1956 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -144,6 +144,22 @@ static int mmc_ios_show(struct seq_file *s, void *data)
}
seq_printf(s, "timing spec:\t%u (%s)\n", ios->timing, str);
+ switch (ios->signal_voltage) {
+ case MMC_SIGNAL_VOLTAGE_330:
+ str = "3.30 V";
+ break;
+ case MMC_SIGNAL_VOLTAGE_180:
+ str = "1.80 V";
+ break;
+ case MMC_SIGNAL_VOLTAGE_120:
+ str = "1.20 V";
+ break;
+ default:
+ str = "invalid";
+ break;
+ }
+ seq_printf(s, "signal voltage:\t%u (%s)\n", ios->chip_select, str);
+
return 0;
}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 7cc46382fd64..e6e39111e05b 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -239,7 +239,7 @@ static void mmc_select_card_type(struct mmc_card *card)
{
struct mmc_host *host = card->host;
u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
- unsigned int caps = host->caps, caps2 = host->caps2;
+ u32 caps = host->caps, caps2 = host->caps2;
unsigned int hs_max_dtr = 0;
if (card_type & EXT_CSD_CARD_TYPE_26)
@@ -491,6 +491,17 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION];
+
+ /*
+ * RPMB regions are defined in multiples of 128K.
+ */
+ card->ext_csd.raw_rpmb_size_mult = ext_csd[EXT_CSD_RPMB_MULT];
+ if (ext_csd[EXT_CSD_RPMB_MULT]) {
+ mmc_part_add(card, ext_csd[EXT_CSD_RPMB_MULT] << 17,
+ EXT_CSD_PART_CONFIG_ACC_RPMB,
+ "rpmb", 0, false,
+ MMC_BLK_DATA_AREA_RPMB);
+ }
}
card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT];
@@ -615,6 +626,8 @@ MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
card->ext_csd.enhanced_area_offset);
MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
+MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
+MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
static struct attribute *mmc_std_attrs[] = {
&dev_attr_cid.attr,
@@ -630,6 +643,8 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_serial.attr,
&dev_attr_enhanced_area_offset.attr,
&dev_attr_enhanced_area_size.attr,
+ &dev_attr_raw_rpmb_size_mult.attr,
+ &dev_attr_rel_sectors.attr,
NULL,
};
@@ -1051,6 +1066,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
if (max_dtr > card->ext_csd.hs_max_dtr)
max_dtr = card->ext_csd.hs_max_dtr;
+ if (mmc_card_highspeed(card) && (max_dtr > 52000000))
+ max_dtr = 52000000;
} else if (max_dtr > card->csd.max_dtr) {
max_dtr = card->csd.max_dtr;
}
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index a0e172042e65..6d8f7012d73a 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -21,6 +21,8 @@
#include "core.h"
#include "mmc_ops.h"
+#define MMC_OPS_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
+
static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
{
int err;
@@ -409,6 +411,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
{
int err;
struct mmc_command cmd = {0};
+ unsigned long timeout;
u32 status;
BUG_ON(!card);
@@ -437,6 +440,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
return 0;
/* Must check status to be sure of no errors */
+ timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
do {
err = mmc_send_status(card, &status);
if (err)
@@ -445,6 +449,13 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
break;
if (mmc_host_is_spi(card->host))
break;
+
+ /* Timeout if the device never leaves the program state. */
+ if (time_after(jiffies, timeout)) {
+ pr_err("%s: Card stuck in programming state! %s\n",
+ mmc_hostname(card->host), __func__);
+ return -ETIMEDOUT;
+ }
} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
if (mmc_host_is_spi(card->host)) {
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index 6bf68799fe97..5e57048e2c1d 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -193,7 +193,21 @@ static int sdio_bus_remove(struct device *dev)
}
#ifdef CONFIG_PM
+
+#ifdef CONFIG_PM_SLEEP
+static int pm_no_operation(struct device *dev)
+{
+ /*
+ * Prevent the PM core from calling SDIO device drivers' suspend
+ * callback routines, which it is not supposed to do, by using this
+ * empty function as the bus type suspend callaback for SDIO.
+ */
+ return 0;
+}
+#endif
+
static const struct dev_pm_ops sdio_bus_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_no_operation, pm_no_operation)
SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend,
pm_generic_runtime_resume,
@@ -258,8 +272,7 @@ static void sdio_release_func(struct device *dev)
sdio_free_func_cis(func);
- if (func->info)
- kfree(func->info);
+ kfree(func->info);
kfree(func);
}
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
index 8f6f5ac131fc..78cb4d5d9d58 100644
--- a/drivers/mmc/core/sdio_io.c
+++ b/drivers/mmc/core/sdio_io.c
@@ -188,8 +188,7 @@ EXPORT_SYMBOL_GPL(sdio_set_block_size);
*/
static inline unsigned int sdio_max_byte_size(struct sdio_func *func)
{
- unsigned mval = min(func->card->host->max_seg_size,
- func->card->host->max_blk_size);
+ unsigned mval = func->card->host->max_blk_size;
if (mmc_blksz_for_byte_mode(func->card))
mval = min(mval, func->cur_blksize);
@@ -311,11 +310,8 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
/* Do the bulk of the transfer using block mode (if supported). */
if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) {
/* Blocks per command is limited by host count, host transfer
- * size (we only use a single sg entry) and the maximum for
- * IO_RW_EXTENDED of 511 blocks. */
- max_blocks = min(func->card->host->max_blk_count,
- func->card->host->max_seg_size / func->cur_blksize);
- max_blocks = min(max_blocks, 511u);
+ * size and the maximum for IO_RW_EXTENDED of 511 blocks. */
+ max_blocks = min(func->card->host->max_blk_count, 511u);
while (remainder >= func->cur_blksize) {
unsigned blocks;
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
index d29e20630eed..62508b457c4f 100644
--- a/drivers/mmc/core/sdio_ops.c
+++ b/drivers/mmc/core/sdio_ops.c
@@ -124,7 +124,10 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
struct mmc_request mrq = {NULL};
struct mmc_command cmd = {0};
struct mmc_data data = {0};
- struct scatterlist sg;
+ struct scatterlist sg, *sg_ptr;
+ struct sg_table sgtable;
+ unsigned int nents, left_size, i;
+ unsigned int seg_size = card->host->max_seg_size;
BUG_ON(!card);
BUG_ON(fn > 7);
@@ -152,15 +155,36 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
/* Code in host drivers/fwk assumes that "blocks" always is >=1 */
data.blocks = blocks ? blocks : 1;
data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
- sg_init_one(&sg, buf, data.blksz * data.blocks);
+ left_size = data.blksz * data.blocks;
+ nents = (left_size - 1) / seg_size + 1;
+ if (nents > 1) {
+ if (sg_alloc_table(&sgtable, nents, GFP_KERNEL))
+ return -ENOMEM;
+
+ data.sg = sgtable.sgl;
+ data.sg_len = nents;
+
+ for_each_sg(data.sg, sg_ptr, data.sg_len, i) {
+ sg_set_page(sg_ptr, virt_to_page(buf + (i * seg_size)),
+ min(seg_size, left_size),
+ offset_in_page(buf + (i * seg_size)));
+ left_size = left_size - seg_size;
+ }
+ } else {
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ sg_init_one(&sg, buf, left_size);
+ }
mmc_set_data_timeout(&data, card);
mmc_wait_for_req(card->host, &mrq);
+ if (nents > 1)
+ sg_free_table(&sgtable);
+
if (cmd.error)
return cmd.error;
if (data.error)
diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c
index 08c6b3dfe080..16a1c0b6f264 100644
--- a/drivers/mmc/core/slot-gpio.c
+++ b/drivers/mmc/core/slot-gpio.c
@@ -27,7 +27,13 @@ struct mmc_gpio {
static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
{
/* Schedule a card detection after a debounce timeout */
- mmc_detect_change(dev_id, msecs_to_jiffies(100));
+ struct mmc_host *host = dev_id;
+
+ if (host->ops->card_event)
+ host->ops->card_event(host);
+
+ mmc_detect_change(host, msecs_to_jiffies(200));
+
return IRQ_HANDLED;
}
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 9bf10e7bbfaf..83eb1e06ff76 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -270,26 +270,8 @@ config MMC_AU1X
If unsure, say N.
-choice
- prompt "Atmel SD/MMC Driver"
- depends on AVR32 || ARCH_AT91
- default MMC_ATMELMCI if AVR32
- help
- Choose which driver to use for the Atmel MCI Silicon
-
-config MMC_AT91
- tristate "AT91 SD/MMC Card Interface support (DEPRECATED)"
- depends on ARCH_AT91
- help
- This selects the AT91 MCI controller. This driver will
- be removed soon (for more information have a look to
- Documentation/feature-removal-schedule.txt). Please use
- MMC_ATMEL_MCI.
-
- If unsure, say N.
-
config MMC_ATMELMCI
- tristate "Atmel Multimedia Card Interface support"
+ tristate "Atmel SD/MMC Driver (Multimedia Card Interface)"
depends on AVR32 || ARCH_AT91
help
This selects the Atmel Multimedia Card Interface driver. If
@@ -298,8 +280,6 @@ config MMC_ATMELMCI
If unsure, say N.
-endchoice
-
config MMC_ATMELMCI_DMA
bool "Atmel MCI DMA support"
depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE
@@ -621,3 +601,14 @@ config MMC_USHC
Note: These controllers only support SDIO cards and do not
support MMC or SD memory cards.
+
+config MMC_WMT
+ tristate "Wondermedia SD/MMC Host Controller support"
+ depends on ARCH_VT8500
+ default y
+ help
+ This selects support for the SD/MMC Host Controller on
+ Wondermedia WM8505/WM8650 based SoCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called wmt-sdmmc.
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 17ad0a7ba40b..39d5e1234709 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -17,7 +17,6 @@ obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_OMAP) += omap.o
obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o
-obj-$(CONFIG_MMC_AT91) += at91_mci.o
obj-$(CONFIG_MMC_ATMELMCI) += atmel-mci.o
obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
obj-$(CONFIG_MMC_MSM) += msm_sdcc.o
@@ -45,6 +44,7 @@ obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
obj-$(CONFIG_MMC_VUB300) += vub300.o
obj-$(CONFIG_MMC_USHC) += ushc.o
+obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o
obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o
obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
deleted file mode 100644
index 74bed0fc23e7..000000000000
--- a/drivers/mmc/host/at91_mci.c
+++ /dev/null
@@ -1,1219 +0,0 @@
-/*
- * linux/drivers/mmc/host/at91_mci.c - ATMEL AT91 MCI Driver
- *
- * Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved
- *
- * Copyright (C) 2006 Malcolm Noyes
- *
- * 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 is the AT91 MCI driver that has been tested with both MMC cards
- and SD-cards. Boards that support write protect are now supported.
- The CCAT91SBC001 board does not support SD cards.
-
- The three entry points are at91_mci_request, at91_mci_set_ios
- and at91_mci_get_ro.
-
- SET IOS
- This configures the device to put it into the correct mode and clock speed
- required.
-
- MCI REQUEST
- MCI request processes the commands sent in the mmc_request structure. This
- can consist of a processing command and a stop command in the case of
- multiple block transfers.
-
- There are three main types of request, commands, reads and writes.
-
- Commands are straight forward. The command is submitted to the controller and
- the request function returns. When the controller generates an interrupt to indicate
- the command is finished, the response to the command are read and the mmc_request_done
- function called to end the request.
-
- Reads and writes work in a similar manner to normal commands but involve the PDC (DMA)
- controller to manage the transfers.
-
- A read is done from the controller directly to the scatterlist passed in from the request.
- Due to a bug in the AT91RM9200 controller, when a read is completed, all the words are byte
- swapped in the scatterlist buffers. AT91SAM926x are not affected by this bug.
-
- The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY
-
- A write is slightly different in that the bytes to write are read from the scatterlist
- into a dma memory buffer (this is in case the source buffer should be read only). The
- entire write buffer is then done from this single dma memory buffer.
-
- The sequence of write interrupts is: ENDTX, TXBUFE, NOTBUSY, CMDRDY
-
- GET RO
- Gets the status of the write protect pin, if available.
-*/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk.h>
-#include <linux/atmel_pdc.h>
-#include <linux/gfp.h>
-#include <linux/highmem.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/sdio.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/gpio.h>
-
-#include <mach/board.h>
-#include <mach/cpu.h>
-
-#include "at91_mci.h"
-
-#define DRIVER_NAME "at91_mci"
-
-static inline int at91mci_is_mci1rev2xx(void)
-{
- return ( cpu_is_at91sam9260()
- || cpu_is_at91sam9263()
- || cpu_is_at91sam9rl()
- || cpu_is_at91sam9g10()
- || cpu_is_at91sam9g20()
- );
-}
-
-#define FL_SENT_COMMAND (1 << 0)
-#define FL_SENT_STOP (1 << 1)
-
-#define AT91_MCI_ERRORS (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE \
- | AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE \
- | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)
-
-#define at91_mci_read(host, reg) __raw_readl((host)->baseaddr + (reg))
-#define at91_mci_write(host, reg, val) __raw_writel((val), (host)->baseaddr + (reg))
-
-#define MCI_BLKSIZE 512
-#define MCI_MAXBLKSIZE 4095
-#define MCI_BLKATONCE 256
-#define MCI_BUFSIZE (MCI_BLKSIZE * MCI_BLKATONCE)
-
-/*
- * Low level type for this driver
- */
-struct at91mci_host
-{
- struct mmc_host *mmc;
- struct mmc_command *cmd;
- struct mmc_request *request;
-
- void __iomem *baseaddr;
- int irq;
-
- struct at91_mmc_data *board;
- int present;
-
- struct clk *mci_clk;
-
- /*
- * Flag indicating when the command has been sent. This is used to
- * work out whether or not to send the stop
- */
- unsigned int flags;
- /* flag for current bus settings */
- u32 bus_mode;
-
- /* DMA buffer used for transmitting */
- unsigned int* buffer;
- dma_addr_t physical_address;
- unsigned int total_length;
-
- /* Latest in the scatterlist that has been enabled for transfer, but not freed */
- int in_use_index;
-
- /* Latest in the scatterlist that has been enabled for transfer */
- int transfer_index;
-
- /* Timer for timeouts */
- struct timer_list timer;
-};
-
-/*
- * Reset the controller and restore most of the state
- */
-static void at91_reset_host(struct at91mci_host *host)
-{
- unsigned long flags;
- u32 mr;
- u32 sdcr;
- u32 dtor;
- u32 imr;
-
- local_irq_save(flags);
- imr = at91_mci_read(host, AT91_MCI_IMR);
-
- at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
-
- /* save current state */
- mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff;
- sdcr = at91_mci_read(host, AT91_MCI_SDCR);
- dtor = at91_mci_read(host, AT91_MCI_DTOR);
-
- /* reset the controller */
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
-
- /* restore state */
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
- at91_mci_write(host, AT91_MCI_MR, mr);
- at91_mci_write(host, AT91_MCI_SDCR, sdcr);
- at91_mci_write(host, AT91_MCI_DTOR, dtor);
- at91_mci_write(host, AT91_MCI_IER, imr);
-
- /* make sure sdio interrupts will fire */
- at91_mci_read(host, AT91_MCI_SR);
-
- local_irq_restore(flags);
-}
-
-static void at91_timeout_timer(unsigned long data)
-{
- struct at91mci_host *host;
-
- host = (struct at91mci_host *)data;
-
- if (host->request) {
- dev_err(host->mmc->parent, "Timeout waiting end of packet\n");
-
- if (host->cmd && host->cmd->data) {
- host->cmd->data->error = -ETIMEDOUT;
- } else {
- if (host->cmd)
- host->cmd->error = -ETIMEDOUT;
- else
- host->request->cmd->error = -ETIMEDOUT;
- }
-
- at91_reset_host(host);
- mmc_request_done(host->mmc, host->request);
- }
-}
-
-/*
- * Copy from sg to a dma block - used for transfers
- */
-static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data)
-{
- unsigned int len, i, size;
- unsigned *dmabuf = host->buffer;
-
- size = data->blksz * data->blocks;
- len = data->sg_len;
-
- /* MCI1 rev2xx Data Write Operation and number of bytes erratum */
- if (at91mci_is_mci1rev2xx())
- if (host->total_length == 12)
- memset(dmabuf, 0, 12);
-
- /*
- * Just loop through all entries. Size might not
- * be the entire list though so make sure that
- * we do not transfer too much.
- */
- for (i = 0; i < len; i++) {
- struct scatterlist *sg;
- int amount;
- unsigned int *sgbuffer;
-
- sg = &data->sg[i];
-
- sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset;
- amount = min(size, sg->length);
- size -= amount;
-
- if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */
- int index;
-
- for (index = 0; index < (amount / 4); index++)
- *dmabuf++ = swab32(sgbuffer[index]);
- } else {
- char *tmpv = (char *)dmabuf;
- memcpy(tmpv, sgbuffer, amount);
- tmpv += amount;
- dmabuf = (unsigned *)tmpv;
- }
-
- kunmap_atomic(sgbuffer);
-
- if (size == 0)
- break;
- }
-
- /*
- * Check that we didn't get a request to transfer
- * more data than can fit into the SG list.
- */
- BUG_ON(size != 0);
-}
-
-/*
- * Handle after a dma read
- */
-static void at91_mci_post_dma_read(struct at91mci_host *host)
-{
- struct mmc_command *cmd;
- struct mmc_data *data;
- unsigned int len, i, size;
- unsigned *dmabuf = host->buffer;
-
- pr_debug("post dma read\n");
-
- cmd = host->cmd;
- if (!cmd) {
- pr_debug("no command\n");
- return;
- }
-
- data = cmd->data;
- if (!data) {
- pr_debug("no data\n");
- return;
- }
-
- size = data->blksz * data->blocks;
- len = data->sg_len;
-
- at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_ENDRX);
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF);
-
- for (i = 0; i < len; i++) {
- struct scatterlist *sg;
- int amount;
- unsigned int *sgbuffer;
-
- sg = &data->sg[i];
-
- sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset;
- amount = min(size, sg->length);
- size -= amount;
-
- if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */
- int index;
- for (index = 0; index < (amount / 4); index++)
- sgbuffer[index] = swab32(*dmabuf++);
- } else {
- char *tmpv = (char *)dmabuf;
- memcpy(sgbuffer, tmpv, amount);
- tmpv += amount;
- dmabuf = (unsigned *)tmpv;
- }
-
- flush_kernel_dcache_page(sg_page(sg));
- kunmap_atomic(sgbuffer);
- data->bytes_xfered += amount;
- if (size == 0)
- break;
- }
-
- pr_debug("post dma read done\n");
-}
-
-/*
- * Handle transmitted data
- */
-static void at91_mci_handle_transmitted(struct at91mci_host *host)
-{
- struct mmc_command *cmd;
- struct mmc_data *data;
-
- pr_debug("Handling the transmit\n");
-
- /* Disable the transfer */
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
-
- /* Now wait for cmd ready */
- at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE);
-
- cmd = host->cmd;
- if (!cmd) return;
-
- data = cmd->data;
- if (!data) return;
-
- if (cmd->data->blocks > 1) {
- pr_debug("multiple write : wait for BLKE...\n");
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE);
- } else
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
-}
-
-/*
- * Update bytes transfered count during a write operation
- */
-static void at91_mci_update_bytes_xfered(struct at91mci_host *host)
-{
- struct mmc_data *data;
-
- /* always deal with the effective request (and not the current cmd) */
-
- if (host->request->cmd && host->request->cmd->error != 0)
- return;
-
- if (host->request->data) {
- data = host->request->data;
- if (data->flags & MMC_DATA_WRITE) {
- /* card is in IDLE mode now */
- pr_debug("-> bytes_xfered %d, total_length = %d\n",
- data->bytes_xfered, host->total_length);
- data->bytes_xfered = data->blksz * data->blocks;
- }
- }
-}
-
-
-/*Handle after command sent ready*/
-static int at91_mci_handle_cmdrdy(struct at91mci_host *host)
-{
- if (!host->cmd)
- return 1;
- else if (!host->cmd->data) {
- if (host->flags & FL_SENT_STOP) {
- /*After multi block write, we must wait for NOTBUSY*/
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
- } else return 1;
- } else if (host->cmd->data->flags & MMC_DATA_WRITE) {
- /*After sendding multi-block-write command, start DMA transfer*/
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_TXBUFE | AT91_MCI_BLKE);
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
- }
-
- /* command not completed, have to wait */
- return 0;
-}
-
-
-/*
- * Enable the controller
- */
-static void at91_mci_enable(struct at91mci_host *host)
-{
- unsigned int mr;
-
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
- at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
- at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
- mr = AT91_MCI_PDCMODE | 0x34a;
-
- if (at91mci_is_mci1rev2xx())
- mr |= AT91_MCI_RDPROOF | AT91_MCI_WRPROOF;
-
- at91_mci_write(host, AT91_MCI_MR, mr);
-
- /* use Slot A or B (only one at same time) */
- at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b);
-}
-
-/*
- * Disable the controller
- */
-static void at91_mci_disable(struct at91mci_host *host)
-{
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
-}
-
-/*
- * Send a command
- */
-static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd)
-{
- unsigned int cmdr, mr;
- unsigned int block_length;
- struct mmc_data *data = cmd->data;
-
- unsigned int blocks;
- unsigned int ier = 0;
-
- host->cmd = cmd;
-
- /* Needed for leaving busy state before CMD1 */
- if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
- pr_debug("Clearing timeout\n");
- at91_mci_write(host, AT91_MCI_ARGR, 0);
- at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD);
- while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
- /* spin */
- pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR));
- }
- }
-
- cmdr = cmd->opcode;
-
- if (mmc_resp_type(cmd) == MMC_RSP_NONE)
- cmdr |= AT91_MCI_RSPTYP_NONE;
- else {
- /* if a response is expected then allow maximum response latancy */
- cmdr |= AT91_MCI_MAXLAT;
- /* set 136 bit response for R2, 48 bit response otherwise */
- if (mmc_resp_type(cmd) == MMC_RSP_R2)
- cmdr |= AT91_MCI_RSPTYP_136;
- else
- cmdr |= AT91_MCI_RSPTYP_48;
- }
-
- if (data) {
-
- if (cpu_is_at91rm9200() || cpu_is_at91sam9261()) {
- if (data->blksz & 0x3) {
- pr_debug("Unsupported block size\n");
- cmd->error = -EINVAL;
- mmc_request_done(host->mmc, host->request);
- return;
- }
- if (data->flags & MMC_DATA_STREAM) {
- pr_debug("Stream commands not supported\n");
- cmd->error = -EINVAL;
- mmc_request_done(host->mmc, host->request);
- return;
- }
- }
-
- block_length = data->blksz;
- blocks = data->blocks;
-
- /* always set data start - also set direction flag for read */
- if (data->flags & MMC_DATA_READ)
- cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START);
- else if (data->flags & MMC_DATA_WRITE)
- cmdr |= AT91_MCI_TRCMD_START;
-
- if (cmd->opcode == SD_IO_RW_EXTENDED) {
- cmdr |= AT91_MCI_TRTYP_SDIO_BLOCK;
- } else {
- if (data->flags & MMC_DATA_STREAM)
- cmdr |= AT91_MCI_TRTYP_STREAM;
- if (data->blocks > 1)
- cmdr |= AT91_MCI_TRTYP_MULTIPLE;
- }
- }
- else {
- block_length = 0;
- blocks = 0;
- }
-
- if (host->flags & FL_SENT_STOP)
- cmdr |= AT91_MCI_TRCMD_STOP;
-
- if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
- cmdr |= AT91_MCI_OPDCMD;
-
- /*
- * Set the arguments and send the command
- */
- pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n",
- cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR));
-
- if (!data) {
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS);
- at91_mci_write(host, ATMEL_PDC_RPR, 0);
- at91_mci_write(host, ATMEL_PDC_RCR, 0);
- at91_mci_write(host, ATMEL_PDC_RNPR, 0);
- at91_mci_write(host, ATMEL_PDC_RNCR, 0);
- at91_mci_write(host, ATMEL_PDC_TPR, 0);
- at91_mci_write(host, ATMEL_PDC_TCR, 0);
- at91_mci_write(host, ATMEL_PDC_TNPR, 0);
- at91_mci_write(host, ATMEL_PDC_TNCR, 0);
- ier = AT91_MCI_CMDRDY;
- } else {
- /* zero block length and PDC mode */
- mr = at91_mci_read(host, AT91_MCI_MR) & 0x5fff;
- mr |= (data->blksz & 0x3) ? AT91_MCI_PDCFBYTE : 0;
- mr |= (block_length << 16);
- mr |= AT91_MCI_PDCMODE;
- at91_mci_write(host, AT91_MCI_MR, mr);
-
- if (!(cpu_is_at91rm9200() || cpu_is_at91sam9261()))
- at91_mci_write(host, AT91_MCI_BLKR,
- AT91_MCI_BLKR_BCNT(blocks) |
- AT91_MCI_BLKR_BLKLEN(block_length));
-
- /*
- * Disable the PDC controller
- */
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
-
- if (cmdr & AT91_MCI_TRCMD_START) {
- data->bytes_xfered = 0;
- host->transfer_index = 0;
- host->in_use_index = 0;
- if (cmdr & AT91_MCI_TRDIR) {
- /*
- * Handle a read
- */
- host->total_length = 0;
-
- at91_mci_write(host, ATMEL_PDC_RPR, host->physical_address);
- at91_mci_write(host, ATMEL_PDC_RCR, (data->blksz & 0x3) ?
- (blocks * block_length) : (blocks * block_length) / 4);
- at91_mci_write(host, ATMEL_PDC_RNPR, 0);
- at91_mci_write(host, ATMEL_PDC_RNCR, 0);
-
- ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */;
- }
- else {
- /*
- * Handle a write
- */
- host->total_length = block_length * blocks;
- /*
- * MCI1 rev2xx Data Write Operation and
- * number of bytes erratum
- */
- if (at91mci_is_mci1rev2xx())
- if (host->total_length < 12)
- host->total_length = 12;
-
- at91_mci_sg_to_dma(host, data);
-
- pr_debug("Transmitting %d bytes\n", host->total_length);
-
- at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);
- at91_mci_write(host, ATMEL_PDC_TCR, (data->blksz & 0x3) ?
- host->total_length : host->total_length / 4);
-
- ier = AT91_MCI_CMDRDY;
- }
- }
- }
-
- /*
- * Send the command and then enable the PDC - not the other way round as
- * the data sheet says
- */
-
- at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
- at91_mci_write(host, AT91_MCI_CMDR, cmdr);
-
- if (cmdr & AT91_MCI_TRCMD_START) {
- if (cmdr & AT91_MCI_TRDIR)
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
- }
-
- /* Enable selected interrupts */
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier);
-}
-
-/*
- * Process the next step in the request
- */
-static void at91_mci_process_next(struct at91mci_host *host)
-{
- if (!(host->flags & FL_SENT_COMMAND)) {
- host->flags |= FL_SENT_COMMAND;
- at91_mci_send_command(host, host->request->cmd);
- }
- else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) {
- host->flags |= FL_SENT_STOP;
- at91_mci_send_command(host, host->request->stop);
- } else {
- del_timer(&host->timer);
- /* the at91rm9200 mci controller hangs after some transfers,
- * and the workaround is to reset it after each transfer.
- */
- if (cpu_is_at91rm9200())
- at91_reset_host(host);
- mmc_request_done(host->mmc, host->request);
- }
-}
-
-/*
- * Handle a command that has been completed
- */
-static void at91_mci_completed_command(struct at91mci_host *host, unsigned int status)
-{
- struct mmc_command *cmd = host->cmd;
- struct mmc_data *data = cmd->data;
-
- at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
-
- cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0));
- cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1));
- cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2));
- cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3));
-
- pr_debug("Status = %08X/%08x [%08X %08X %08X %08X]\n",
- status, at91_mci_read(host, AT91_MCI_SR),
- cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
-
- if (status & AT91_MCI_ERRORS) {
- if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) {
- cmd->error = 0;
- }
- else {
- if (status & (AT91_MCI_DTOE | AT91_MCI_DCRCE)) {
- if (data) {
- if (status & AT91_MCI_DTOE)
- data->error = -ETIMEDOUT;
- else if (status & AT91_MCI_DCRCE)
- data->error = -EILSEQ;
- }
- } else {
- if (status & AT91_MCI_RTOE)
- cmd->error = -ETIMEDOUT;
- else if (status & AT91_MCI_RCRCE)
- cmd->error = -EILSEQ;
- else
- cmd->error = -EIO;
- }
-
- pr_debug("Error detected and set to %d/%d (cmd = %d, retries = %d)\n",
- cmd->error, data ? data->error : 0,
- cmd->opcode, cmd->retries);
- }
- }
- else
- cmd->error = 0;
-
- at91_mci_process_next(host);
-}
-
-/*
- * Handle an MMC request
- */
-static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct at91mci_host *host = mmc_priv(mmc);
- host->request = mrq;
- host->flags = 0;
-
- /* more than 1s timeout needed with slow SD cards */
- mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000));
-
- at91_mci_process_next(host);
-}
-
-/*
- * Set the IOS
- */
-static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- int clkdiv;
- struct at91mci_host *host = mmc_priv(mmc);
- unsigned long at91_master_clock = clk_get_rate(host->mci_clk);
-
- host->bus_mode = ios->bus_mode;
-
- if (ios->clock == 0) {
- /* Disable the MCI controller */
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS);
- clkdiv = 0;
- }
- else {
- /* Enable the MCI controller */
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
-
- if ((at91_master_clock % (ios->clock * 2)) == 0)
- clkdiv = ((at91_master_clock / ios->clock) / 2) - 1;
- else
- clkdiv = (at91_master_clock / ios->clock) / 2;
-
- pr_debug("clkdiv = %d. mcck = %ld\n", clkdiv,
- at91_master_clock / (2 * (clkdiv + 1)));
- }
- if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) {
- pr_debug("MMC: Setting controller bus width to 4\n");
- at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) | AT91_MCI_SDCBUS);
- }
- else {
- pr_debug("MMC: Setting controller bus width to 1\n");
- at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
- }
-
- /* Set the clock divider */
- at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);
-
- /* maybe switch power to the card */
- if (gpio_is_valid(host->board->vcc_pin)) {
- switch (ios->power_mode) {
- case MMC_POWER_OFF:
- gpio_set_value(host->board->vcc_pin, 0);
- break;
- case MMC_POWER_UP:
- gpio_set_value(host->board->vcc_pin, 1);
- break;
- case MMC_POWER_ON:
- break;
- default:
- WARN_ON(1);
- }
- }
-}
-
-/*
- * Handle an interrupt
- */
-static irqreturn_t at91_mci_irq(int irq, void *devid)
-{
- struct at91mci_host *host = devid;
- int completed = 0;
- unsigned int int_status, int_mask;
-
- int_status = at91_mci_read(host, AT91_MCI_SR);
- int_mask = at91_mci_read(host, AT91_MCI_IMR);
-
- pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask,
- int_status & int_mask);
-
- int_status = int_status & int_mask;
-
- if (int_status & AT91_MCI_ERRORS) {
- completed = 1;
-
- if (int_status & AT91_MCI_UNRE)
- pr_debug("MMC: Underrun error\n");
- if (int_status & AT91_MCI_OVRE)
- pr_debug("MMC: Overrun error\n");
- if (int_status & AT91_MCI_DTOE)
- pr_debug("MMC: Data timeout\n");
- if (int_status & AT91_MCI_DCRCE)
- pr_debug("MMC: CRC error in data\n");
- if (int_status & AT91_MCI_RTOE)
- pr_debug("MMC: Response timeout\n");
- if (int_status & AT91_MCI_RENDE)
- pr_debug("MMC: Response end bit error\n");
- if (int_status & AT91_MCI_RCRCE)
- pr_debug("MMC: Response CRC error\n");
- if (int_status & AT91_MCI_RDIRE)
- pr_debug("MMC: Response direction error\n");
- if (int_status & AT91_MCI_RINDE)
- pr_debug("MMC: Response index error\n");
- } else {
- /* Only continue processing if no errors */
-
- if (int_status & AT91_MCI_TXBUFE) {
- pr_debug("TX buffer empty\n");
- at91_mci_handle_transmitted(host);
- }
-
- if (int_status & AT91_MCI_ENDRX) {
- pr_debug("ENDRX\n");
- at91_mci_post_dma_read(host);
- }
-
- if (int_status & AT91_MCI_RXBUFF) {
- pr_debug("RX buffer full\n");
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
- at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_RXBUFF | AT91_MCI_ENDRX);
- completed = 1;
- }
-
- if (int_status & AT91_MCI_ENDTX)
- pr_debug("Transmit has ended\n");
-
- if (int_status & AT91_MCI_NOTBUSY) {
- pr_debug("Card is ready\n");
- at91_mci_update_bytes_xfered(host);
- completed = 1;
- }
-
- if (int_status & AT91_MCI_DTIP)
- pr_debug("Data transfer in progress\n");
-
- if (int_status & AT91_MCI_BLKE) {
- pr_debug("Block transfer has ended\n");
- if (host->request->data && host->request->data->blocks > 1) {
- /* multi block write : complete multi write
- * command and send stop */
- completed = 1;
- } else {
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
- }
- }
-
- if (int_status & AT91_MCI_SDIOIRQA)
- mmc_signal_sdio_irq(host->mmc);
-
- if (int_status & AT91_MCI_SDIOIRQB)
- mmc_signal_sdio_irq(host->mmc);
-
- if (int_status & AT91_MCI_TXRDY)
- pr_debug("Ready to transmit\n");
-
- if (int_status & AT91_MCI_RXRDY)
- pr_debug("Ready to receive\n");
-
- if (int_status & AT91_MCI_CMDRDY) {
- pr_debug("Command ready\n");
- completed = at91_mci_handle_cmdrdy(host);
- }
- }
-
- if (completed) {
- pr_debug("Completed command\n");
- at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
- at91_mci_completed_command(host, int_status);
- } else
- at91_mci_write(host, AT91_MCI_IDR, int_status & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t at91_mmc_det_irq(int irq, void *_host)
-{
- struct at91mci_host *host = _host;
- int present;
-
- /* entering this ISR means that we have configured det_pin:
- * we can use its value in board structure */
- present = !gpio_get_value(host->board->det_pin);
-
- /*
- * we expect this irq on both insert and remove,
- * and use a short delay to debounce.
- */
- if (present != host->present) {
- host->present = present;
- pr_debug("%s: card %s\n", mmc_hostname(host->mmc),
- present ? "insert" : "remove");
- if (!present) {
- pr_debug("****** Resetting SD-card bus width ******\n");
- at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
- }
- /* 0.5s needed because of early card detect switch firing */
- mmc_detect_change(host->mmc, msecs_to_jiffies(500));
- }
- return IRQ_HANDLED;
-}
-
-static int at91_mci_get_ro(struct mmc_host *mmc)
-{
- struct at91mci_host *host = mmc_priv(mmc);
-
- if (gpio_is_valid(host->board->wp_pin))
- return !!gpio_get_value(host->board->wp_pin);
- /*
- * Board doesn't support read only detection; let the mmc core
- * decide what to do.
- */
- return -ENOSYS;
-}
-
-static void at91_mci_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct at91mci_host *host = mmc_priv(mmc);
-
- pr_debug("%s: sdio_irq %c : %s\n", mmc_hostname(host->mmc),
- host->board->slot_b ? 'B':'A', enable ? "enable" : "disable");
- at91_mci_write(host, enable ? AT91_MCI_IER : AT91_MCI_IDR,
- host->board->slot_b ? AT91_MCI_SDIOIRQB : AT91_MCI_SDIOIRQA);
-
-}
-
-static const struct mmc_host_ops at91_mci_ops = {
- .request = at91_mci_request,
- .set_ios = at91_mci_set_ios,
- .get_ro = at91_mci_get_ro,
- .enable_sdio_irq = at91_mci_enable_sdio_irq,
-};
-
-/*
- * Probe for the device
- */
-static int __init at91_mci_probe(struct platform_device *pdev)
-{
- struct mmc_host *mmc;
- struct at91mci_host *host;
- struct resource *res;
- int ret;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENXIO;
-
- if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME))
- return -EBUSY;
-
- mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
- if (!mmc) {
- ret = -ENOMEM;
- dev_dbg(&pdev->dev, "couldn't allocate mmc host\n");
- goto fail6;
- }
-
- mmc->ops = &at91_mci_ops;
- mmc->f_min = 375000;
- mmc->f_max = 25000000;
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps = 0;
-
- mmc->max_blk_size = MCI_MAXBLKSIZE;
- mmc->max_blk_count = MCI_BLKATONCE;
- mmc->max_req_size = MCI_BUFSIZE;
- mmc->max_segs = MCI_BLKATONCE;
- mmc->max_seg_size = MCI_BUFSIZE;
-
- host = mmc_priv(mmc);
- host->mmc = mmc;
- host->bus_mode = 0;
- host->board = pdev->dev.platform_data;
- if (host->board->wire4) {
- if (at91mci_is_mci1rev2xx())
- mmc->caps |= MMC_CAP_4_BIT_DATA;
- else
- dev_warn(&pdev->dev, "4 wire bus mode not supported"
- " - using 1 wire\n");
- }
-
- host->buffer = dma_alloc_coherent(&pdev->dev, MCI_BUFSIZE,
- &host->physical_address, GFP_KERNEL);
- if (!host->buffer) {
- ret = -ENOMEM;
- dev_err(&pdev->dev, "Can't allocate transmit buffer\n");
- goto fail5;
- }
-
- /* Add SDIO capability when available */
- if (at91mci_is_mci1rev2xx()) {
- /* at91mci MCI1 rev2xx sdio interrupt erratum */
- if (host->board->wire4 || !host->board->slot_b)
- mmc->caps |= MMC_CAP_SDIO_IRQ;
- }
-
- /*
- * Reserve GPIOs ... board init code makes sure these pins are set
- * up as GPIOs with the right direction (input, except for vcc)
- */
- if (gpio_is_valid(host->board->det_pin)) {
- ret = gpio_request(host->board->det_pin, "mmc_detect");
- if (ret < 0) {
- dev_dbg(&pdev->dev, "couldn't claim card detect pin\n");
- goto fail4b;
- }
- }
- if (gpio_is_valid(host->board->wp_pin)) {
- ret = gpio_request(host->board->wp_pin, "mmc_wp");
- if (ret < 0) {
- dev_dbg(&pdev->dev, "couldn't claim wp sense pin\n");
- goto fail4;
- }
- }
- if (gpio_is_valid(host->board->vcc_pin)) {
- ret = gpio_request(host->board->vcc_pin, "mmc_vcc");
- if (ret < 0) {
- dev_dbg(&pdev->dev, "couldn't claim vcc switch pin\n");
- goto fail3;
- }
- }
-
- /*
- * Get Clock
- */
- host->mci_clk = clk_get(&pdev->dev, "mci_clk");
- if (IS_ERR(host->mci_clk)) {
- ret = -ENODEV;
- dev_dbg(&pdev->dev, "no mci_clk?\n");
- goto fail2;
- }
-
- /*
- * Map I/O region
- */
- host->baseaddr = ioremap(res->start, resource_size(res));
- if (!host->baseaddr) {
- ret = -ENOMEM;
- goto fail1;
- }
-
- /*
- * Reset hardware
- */
- clk_enable(host->mci_clk); /* Enable the peripheral clock */
- at91_mci_disable(host);
- at91_mci_enable(host);
-
- /*
- * Allocate the MCI interrupt
- */
- host->irq = platform_get_irq(pdev, 0);
- ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED,
- mmc_hostname(mmc), host);
- if (ret) {
- dev_dbg(&pdev->dev, "request MCI interrupt failed\n");
- goto fail0;
- }
-
- setup_timer(&host->timer, at91_timeout_timer, (unsigned long)host);
-
- platform_set_drvdata(pdev, mmc);
-
- /*
- * Add host to MMC layer
- */
- if (gpio_is_valid(host->board->det_pin)) {
- host->present = !gpio_get_value(host->board->det_pin);
- }
- else
- host->present = -1;
-
- mmc_add_host(mmc);
-
- /*
- * monitor card insertion/removal if we can
- */
- if (gpio_is_valid(host->board->det_pin)) {
- ret = request_irq(gpio_to_irq(host->board->det_pin),
- at91_mmc_det_irq, 0, mmc_hostname(mmc), host);
- if (ret)
- dev_warn(&pdev->dev, "request MMC detect irq failed\n");
- else
- device_init_wakeup(&pdev->dev, 1);
- }
-
- pr_debug("Added MCI driver\n");
-
- return 0;
-
-fail0:
- clk_disable(host->mci_clk);
- iounmap(host->baseaddr);
-fail1:
- clk_put(host->mci_clk);
-fail2:
- if (gpio_is_valid(host->board->vcc_pin))
- gpio_free(host->board->vcc_pin);
-fail3:
- if (gpio_is_valid(host->board->wp_pin))
- gpio_free(host->board->wp_pin);
-fail4:
- if (gpio_is_valid(host->board->det_pin))
- gpio_free(host->board->det_pin);
-fail4b:
- if (host->buffer)
- dma_free_coherent(&pdev->dev, MCI_BUFSIZE,
- host->buffer, host->physical_address);
-fail5:
- mmc_free_host(mmc);
-fail6:
- release_mem_region(res->start, resource_size(res));
- dev_err(&pdev->dev, "probe failed, err %d\n", ret);
- return ret;
-}
-
-/*
- * Remove a device
- */
-static int __exit at91_mci_remove(struct platform_device *pdev)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- struct at91mci_host *host;
- struct resource *res;
-
- if (!mmc)
- return -1;
-
- host = mmc_priv(mmc);
-
- if (host->buffer)
- dma_free_coherent(&pdev->dev, MCI_BUFSIZE,
- host->buffer, host->physical_address);
-
- if (gpio_is_valid(host->board->det_pin)) {
- if (device_can_wakeup(&pdev->dev))
- free_irq(gpio_to_irq(host->board->det_pin), host);
- device_init_wakeup(&pdev->dev, 0);
- gpio_free(host->board->det_pin);
- }
-
- at91_mci_disable(host);
- del_timer_sync(&host->timer);
- mmc_remove_host(mmc);
- free_irq(host->irq, host);
-
- clk_disable(host->mci_clk); /* Disable the peripheral clock */
- clk_put(host->mci_clk);
-
- if (gpio_is_valid(host->board->vcc_pin))
- gpio_free(host->board->vcc_pin);
- if (gpio_is_valid(host->board->wp_pin))
- gpio_free(host->board->wp_pin);
-
- iounmap(host->baseaddr);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
- mmc_free_host(mmc);
- platform_set_drvdata(pdev, NULL);
- pr_debug("MCI Removed\n");
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- struct at91mci_host *host = mmc_priv(mmc);
- int ret = 0;
-
- if (gpio_is_valid(host->board->det_pin) && device_may_wakeup(&pdev->dev))
- enable_irq_wake(host->board->det_pin);
-
- if (mmc)
- ret = mmc_suspend_host(mmc);
-
- return ret;
-}
-
-static int at91_mci_resume(struct platform_device *pdev)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- struct at91mci_host *host = mmc_priv(mmc);
- int ret = 0;
-
- if (gpio_is_valid(host->board->det_pin) && device_may_wakeup(&pdev->dev))
- disable_irq_wake(host->board->det_pin);
-
- if (mmc)
- ret = mmc_resume_host(mmc);
-
- return ret;
-}
-#else
-#define at91_mci_suspend NULL
-#define at91_mci_resume NULL
-#endif
-
-static struct platform_driver at91_mci_driver = {
- .remove = __exit_p(at91_mci_remove),
- .suspend = at91_mci_suspend,
- .resume = at91_mci_resume,
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-static int __init at91_mci_init(void)
-{
- return platform_driver_probe(&at91_mci_driver, at91_mci_probe);
-}
-
-static void __exit at91_mci_exit(void)
-{
- platform_driver_unregister(&at91_mci_driver);
-}
-
-module_init(at91_mci_init);
-module_exit(at91_mci_exit);
-
-MODULE_DESCRIPTION("AT91 Multimedia Card Interface driver");
-MODULE_AUTHOR("Nick Randell");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:at91_mci");
diff --git a/drivers/mmc/host/at91_mci.h b/drivers/mmc/host/at91_mci.h
deleted file mode 100644
index eec3a6b1c2bc..000000000000
--- a/drivers/mmc/host/at91_mci.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * drivers/mmc/host/at91_mci.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * MultiMedia Card Interface (MCI) registers.
- * Based on AT91RM9200 datasheet revision F.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef AT91_MCI_H
-#define AT91_MCI_H
-
-#define AT91_MCI_CR 0x00 /* Control Register */
-#define AT91_MCI_MCIEN (1 << 0) /* Multi-Media Interface Enable */
-#define AT91_MCI_MCIDIS (1 << 1) /* Multi-Media Interface Disable */
-#define AT91_MCI_PWSEN (1 << 2) /* Power Save Mode Enable */
-#define AT91_MCI_PWSDIS (1 << 3) /* Power Save Mode Disable */
-#define AT91_MCI_SWRST (1 << 7) /* Software Reset */
-
-#define AT91_MCI_MR 0x04 /* Mode Register */
-#define AT91_MCI_CLKDIV (0xff << 0) /* Clock Divider */
-#define AT91_MCI_PWSDIV (7 << 8) /* Power Saving Divider */
-#define AT91_MCI_RDPROOF (1 << 11) /* Read Proof Enable [SAM926[03] only] */
-#define AT91_MCI_WRPROOF (1 << 12) /* Write Proof Enable [SAM926[03] only] */
-#define AT91_MCI_PDCFBYTE (1 << 13) /* PDC Force Byte Transfer [SAM926[03] only] */
-#define AT91_MCI_PDCPADV (1 << 14) /* PDC Padding Value */
-#define AT91_MCI_PDCMODE (1 << 15) /* PDC-orientated Mode */
-#define AT91_MCI_BLKLEN (0xfff << 18) /* Data Block Length */
-
-#define AT91_MCI_DTOR 0x08 /* Data Timeout Register */
-#define AT91_MCI_DTOCYC (0xf << 0) /* Data Timeout Cycle Number */
-#define AT91_MCI_DTOMUL (7 << 4) /* Data Timeout Multiplier */
-#define AT91_MCI_DTOMUL_1 (0 << 4)
-#define AT91_MCI_DTOMUL_16 (1 << 4)
-#define AT91_MCI_DTOMUL_128 (2 << 4)
-#define AT91_MCI_DTOMUL_256 (3 << 4)
-#define AT91_MCI_DTOMUL_1K (4 << 4)
-#define AT91_MCI_DTOMUL_4K (5 << 4)
-#define AT91_MCI_DTOMUL_64K (6 << 4)
-#define AT91_MCI_DTOMUL_1M (7 << 4)
-
-#define AT91_MCI_SDCR 0x0c /* SD Card Register */
-#define AT91_MCI_SDCSEL (3 << 0) /* SD Card Selector */
-#define AT91_MCI_SDCBUS (1 << 7) /* 1-bit or 4-bit bus */
-
-#define AT91_MCI_ARGR 0x10 /* Argument Register */
-
-#define AT91_MCI_CMDR 0x14 /* Command Register */
-#define AT91_MCI_CMDNB (0x3f << 0) /* Command Number */
-#define AT91_MCI_RSPTYP (3 << 6) /* Response Type */
-#define AT91_MCI_RSPTYP_NONE (0 << 6)
-#define AT91_MCI_RSPTYP_48 (1 << 6)
-#define AT91_MCI_RSPTYP_136 (2 << 6)
-#define AT91_MCI_SPCMD (7 << 8) /* Special Command */
-#define AT91_MCI_SPCMD_NONE (0 << 8)
-#define AT91_MCI_SPCMD_INIT (1 << 8)
-#define AT91_MCI_SPCMD_SYNC (2 << 8)
-#define AT91_MCI_SPCMD_ICMD (4 << 8)
-#define AT91_MCI_SPCMD_IRESP (5 << 8)
-#define AT91_MCI_OPDCMD (1 << 11) /* Open Drain Command */
-#define AT91_MCI_MAXLAT (1 << 12) /* Max Latency for Command to Response */
-#define AT91_MCI_TRCMD (3 << 16) /* Transfer Command */
-#define AT91_MCI_TRCMD_NONE (0 << 16)
-#define AT91_MCI_TRCMD_START (1 << 16)
-#define AT91_MCI_TRCMD_STOP (2 << 16)
-#define AT91_MCI_TRDIR (1 << 18) /* Transfer Direction */
-#define AT91_MCI_TRTYP (3 << 19) /* Transfer Type */
-#define AT91_MCI_TRTYP_BLOCK (0 << 19)
-#define AT91_MCI_TRTYP_MULTIPLE (1 << 19)
-#define AT91_MCI_TRTYP_STREAM (2 << 19)
-#define AT91_MCI_TRTYP_SDIO_BYTE (4 << 19)
-#define AT91_MCI_TRTYP_SDIO_BLOCK (5 << 19)
-
-#define AT91_MCI_BLKR 0x18 /* Block Register */
-#define AT91_MCI_BLKR_BCNT(n) ((0xffff & (n)) << 0) /* Block count */
-#define AT91_MCI_BLKR_BLKLEN(n) ((0xffff & (n)) << 16) /* Block length */
-
-#define AT91_MCI_RSPR(n) (0x20 + ((n) * 4)) /* Response Registers 0-3 */
-#define AT91_MCR_RDR 0x30 /* Receive Data Register */
-#define AT91_MCR_TDR 0x34 /* Transmit Data Register */
-
-#define AT91_MCI_SR 0x40 /* Status Register */
-#define AT91_MCI_CMDRDY (1 << 0) /* Command Ready */
-#define AT91_MCI_RXRDY (1 << 1) /* Receiver Ready */
-#define AT91_MCI_TXRDY (1 << 2) /* Transmit Ready */
-#define AT91_MCI_BLKE (1 << 3) /* Data Block Ended */
-#define AT91_MCI_DTIP (1 << 4) /* Data Transfer in Progress */
-#define AT91_MCI_NOTBUSY (1 << 5) /* Data Not Busy */
-#define AT91_MCI_ENDRX (1 << 6) /* End of RX Buffer */
-#define AT91_MCI_ENDTX (1 << 7) /* End fo TX Buffer */
-#define AT91_MCI_SDIOIRQA (1 << 8) /* SDIO Interrupt for Slot A */
-#define AT91_MCI_SDIOIRQB (1 << 9) /* SDIO Interrupt for Slot B */
-#define AT91_MCI_RXBUFF (1 << 14) /* RX Buffer Full */
-#define AT91_MCI_TXBUFE (1 << 15) /* TX Buffer Empty */
-#define AT91_MCI_RINDE (1 << 16) /* Response Index Error */
-#define AT91_MCI_RDIRE (1 << 17) /* Response Direction Error */
-#define AT91_MCI_RCRCE (1 << 18) /* Response CRC Error */
-#define AT91_MCI_RENDE (1 << 19) /* Response End Bit Error */
-#define AT91_MCI_RTOE (1 << 20) /* Response Time-out Error */
-#define AT91_MCI_DCRCE (1 << 21) /* Data CRC Error */
-#define AT91_MCI_DTOE (1 << 22) /* Data Time-out Error */
-#define AT91_MCI_OVRE (1 << 30) /* Overrun */
-#define AT91_MCI_UNRE (1 << 31) /* Underrun */
-
-#define AT91_MCI_IER 0x44 /* Interrupt Enable Register */
-#define AT91_MCI_IDR 0x48 /* Interrupt Disable Register */
-#define AT91_MCI_IMR 0x4c /* Interrupt Mask Register */
-
-#endif
diff --git a/drivers/mmc/host/dw_mmc-pci.c b/drivers/mmc/host/dw_mmc-pci.c
index edb37e9135ae..53a09cbb2c7c 100644
--- a/drivers/mmc/host/dw_mmc-pci.c
+++ b/drivers/mmc/host/dw_mmc-pci.c
@@ -134,7 +134,7 @@ static struct pci_driver dw_mci_pci_driver = {
.name = "dw_mmc_pci",
.id_table = dw_mci_pci_id,
.probe = dw_mci_pci_probe,
- .remove = dw_mci_pci_remove,
+ .remove = __devexit_p(dw_mci_pci_remove),
.driver = {
.pm = &dw_mci_pci_pmops
},
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 917936bee5d5..4e133709e33d 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -119,7 +119,8 @@ static const struct of_device_id dw_mci_pltfm_match[] = {
MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
static struct platform_driver dw_mci_pltfm_driver = {
- .remove = __exit_p(dw_mci_pltfm_remove),
+ .probe = dw_mci_pltfm_probe,
+ .remove = __devexit_p(dw_mci_pltfm_remove),
.driver = {
.name = "dw_mmc",
.of_match_table = of_match_ptr(dw_mci_pltfm_match),
@@ -127,18 +128,7 @@ static struct platform_driver dw_mci_pltfm_driver = {
},
};
-static int __init dw_mci_init(void)
-{
- return platform_driver_probe(&dw_mci_pltfm_driver, dw_mci_pltfm_probe);
-}
-
-static void __exit dw_mci_exit(void)
-{
- platform_driver_unregister(&dw_mci_pltfm_driver);
-}
-
-module_init(dw_mci_init);
-module_exit(dw_mci_exit);
+module_platform_driver(dw_mci_pltfm_driver);
MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
MODULE_AUTHOR("NXP Semiconductor VietNam");
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index c0667c8af2bd..323c5022c2ca 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -232,7 +232,7 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
{
struct mmc_data *data;
struct dw_mci_slot *slot = mmc_priv(mmc);
- struct dw_mci_drv_data *drv_data = slot->host->drv_data;
+ const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
u32 cmdr;
cmd->error = -EINPROGRESS;
@@ -617,13 +617,13 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
cmd, arg, cmd_status);
}
-static void dw_mci_setup_bus(struct dw_mci_slot *slot)
+static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
{
struct dw_mci *host = slot->host;
u32 div;
u32 clk_en_a;
- if (slot->clock != host->current_speed) {
+ if (slot->clock != host->current_speed || force_clkinit) {
div = host->bus_hz / slot->clock;
if (host->bus_hz % slot->clock && host->bus_hz > slot->clock)
/*
@@ -683,9 +683,6 @@ static void __dw_mci_start_request(struct dw_mci *host,
if (host->pdata->select_slot)
host->pdata->select_slot(slot->id);
- /* Slot specific timing and width adjustment */
- dw_mci_setup_bus(slot);
-
host->cur_slot = slot;
host->mrq = mrq;
@@ -773,22 +770,19 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct dw_mci_slot *slot = mmc_priv(mmc);
- struct dw_mci_drv_data *drv_data = slot->host->drv_data;
+ const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
u32 regs;
- /* set default 1 bit mode */
- slot->ctype = SDMMC_CTYPE_1BIT;
-
switch (ios->bus_width) {
- case MMC_BUS_WIDTH_1:
- slot->ctype = SDMMC_CTYPE_1BIT;
- break;
case MMC_BUS_WIDTH_4:
slot->ctype = SDMMC_CTYPE_4BIT;
break;
case MMC_BUS_WIDTH_8:
slot->ctype = SDMMC_CTYPE_8BIT;
break;
+ default:
+ /* set default 1 bit mode */
+ slot->ctype = SDMMC_CTYPE_1BIT;
}
regs = mci_readl(slot->host, UHS_REG);
@@ -812,6 +806,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (drv_data && drv_data->set_ios)
drv_data->set_ios(slot->host, ios);
+ /* Slot specific timing and width adjustment */
+ dw_mci_setup_bus(slot, false);
+
switch (ios->power_mode) {
case MMC_POWER_UP:
set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
@@ -1817,7 +1814,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
{
struct mmc_host *mmc;
struct dw_mci_slot *slot;
- struct dw_mci_drv_data *drv_data = host->drv_data;
+ const struct dw_mci_drv_data *drv_data = host->drv_data;
int ctrl_id, ret;
u8 bus_width;
@@ -1850,6 +1847,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
if (host->pdata->caps)
mmc->caps = host->pdata->caps;
+ if (host->pdata->pm_caps)
+ mmc->pm_caps = host->pdata->pm_caps;
+
if (host->dev->of_node) {
ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
if (ctrl_id < 0)
@@ -1911,7 +1911,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
#endif /* CONFIG_MMC_DW_IDMAC */
}
- host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
+ host->vmmc = devm_regulator_get(mmc_dev(mmc), "vmmc");
if (IS_ERR(host->vmmc)) {
pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
host->vmmc = NULL;
@@ -1960,7 +1960,7 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
static void dw_mci_init_dma(struct dw_mci *host)
{
/* Alloc memory for sg translation */
- host->sg_cpu = dma_alloc_coherent(host->dev, PAGE_SIZE,
+ host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
&host->sg_dma, GFP_KERNEL);
if (!host->sg_cpu) {
dev_err(host->dev, "%s: could not alloc DMA memory\n",
@@ -2038,7 +2038,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
struct dw_mci_board *pdata;
struct device *dev = host->dev;
struct device_node *np = dev->of_node;
- struct dw_mci_drv_data *drv_data = host->drv_data;
+ const struct dw_mci_drv_data *drv_data = host->drv_data;
int idx, ret;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
@@ -2072,6 +2072,12 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
return ERR_PTR(ret);
}
+ if (of_find_property(np, "keep-power-in-suspend", NULL))
+ pdata->pm_caps |= MMC_PM_KEEP_POWER;
+
+ if (of_find_property(np, "enable-sdio-wakeup", NULL))
+ pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
+
return pdata;
}
@@ -2084,7 +2090,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
int dw_mci_probe(struct dw_mci *host)
{
- struct dw_mci_drv_data *drv_data = host->drv_data;
+ const struct dw_mci_drv_data *drv_data = host->drv_data;
int width, i, ret = 0;
u32 fifo_size;
int init_slots = 0;
@@ -2103,26 +2109,24 @@ int dw_mci_probe(struct dw_mci *host)
return -ENODEV;
}
- host->biu_clk = clk_get(host->dev, "biu");
+ host->biu_clk = devm_clk_get(host->dev, "biu");
if (IS_ERR(host->biu_clk)) {
dev_dbg(host->dev, "biu clock not available\n");
} else {
ret = clk_prepare_enable(host->biu_clk);
if (ret) {
dev_err(host->dev, "failed to enable biu clock\n");
- clk_put(host->biu_clk);
return ret;
}
}
- host->ciu_clk = clk_get(host->dev, "ciu");
+ host->ciu_clk = devm_clk_get(host->dev, "ciu");
if (IS_ERR(host->ciu_clk)) {
dev_dbg(host->dev, "ciu clock not available\n");
} else {
ret = clk_prepare_enable(host->ciu_clk);
if (ret) {
dev_err(host->dev, "failed to enable ciu clock\n");
- clk_put(host->ciu_clk);
goto err_clk_biu;
}
}
@@ -2224,7 +2228,8 @@ int dw_mci_probe(struct dw_mci *host)
if (!host->card_workqueue)
goto err_dmaunmap;
INIT_WORK(&host->card_work, dw_mci_work_routine_card);
- ret = request_irq(host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host);
+ ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
+ host->irq_flags, "dw-mci", host);
if (ret)
goto err_workqueue;
@@ -2262,7 +2267,7 @@ int dw_mci_probe(struct dw_mci *host)
} else {
dev_dbg(host->dev, "attempted to initialize %d slots, "
"but failed on all\n", host->num_slots);
- goto err_init_slot;
+ goto err_workqueue;
}
/*
@@ -2282,33 +2287,24 @@ int dw_mci_probe(struct dw_mci *host)
return 0;
-err_init_slot:
- free_irq(host->irq, host);
-
err_workqueue:
destroy_workqueue(host->card_workqueue);
err_dmaunmap:
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
- dma_free_coherent(host->dev, PAGE_SIZE,
- host->sg_cpu, host->sg_dma);
- if (host->vmmc) {
+ if (host->vmmc)
regulator_disable(host->vmmc);
- regulator_put(host->vmmc);
- }
err_clk_ciu:
- if (!IS_ERR(host->ciu_clk)) {
+ if (!IS_ERR(host->ciu_clk))
clk_disable_unprepare(host->ciu_clk);
- clk_put(host->ciu_clk);
- }
+
err_clk_biu:
- if (!IS_ERR(host->biu_clk)) {
+ if (!IS_ERR(host->biu_clk))
clk_disable_unprepare(host->biu_clk);
- clk_put(host->biu_clk);
- }
+
return ret;
}
EXPORT_SYMBOL(dw_mci_probe);
@@ -2330,24 +2326,19 @@ void dw_mci_remove(struct dw_mci *host)
mci_writel(host, CLKENA, 0);
mci_writel(host, CLKSRC, 0);
- free_irq(host->irq, host);
destroy_workqueue(host->card_workqueue);
- dma_free_coherent(host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
- if (host->vmmc) {
+ if (host->vmmc)
regulator_disable(host->vmmc);
- regulator_put(host->vmmc);
- }
if (!IS_ERR(host->ciu_clk))
clk_disable_unprepare(host->ciu_clk);
+
if (!IS_ERR(host->biu_clk))
clk_disable_unprepare(host->biu_clk);
- clk_put(host->ciu_clk);
- clk_put(host->biu_clk);
}
EXPORT_SYMBOL(dw_mci_remove);
@@ -2411,6 +2402,11 @@ int dw_mci_resume(struct dw_mci *host)
struct dw_mci_slot *slot = host->slot[i];
if (!slot)
continue;
+ if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
+ dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
+ dw_mci_setup_bus(slot, true);
+ }
+
ret = mmc_resume_host(host->slot[i]->mmc);
if (ret < 0)
return ret;
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 6290b7f1ccfe..29e680f193a0 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -240,7 +240,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
return 0;
for_each_sg(data->sg, sg, data->sg_len, i) {
- if (sg->offset & 3 || sg->length & 3) {
+ if (sg->offset & 3 || sg->length & 3 || sg->length < 512) {
host->do_dma = 0;
return 0;
}
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index 80d1e6d4b0ae..206fe499ded5 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -43,7 +43,6 @@
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
#include <linux/stmp_device.h>
-#include <linux/mmc/mxs-mmc.h>
#include <linux/spi/mxs-spi.h>
#define DRIVER_NAME "mxs-mmc"
@@ -593,13 +592,13 @@ static int mxs_mmc_probe(struct platform_device *pdev)
struct mxs_mmc_host *host;
struct mmc_host *mmc;
struct resource *iores, *dmares;
- struct mxs_mmc_platform_data *pdata;
struct pinctrl *pinctrl;
int ret = 0, irq_err, irq_dma;
dma_cap_mask_t mask;
struct regulator *reg_vmmc;
enum of_gpio_flags flags;
struct mxs_ssp *ssp;
+ u32 bus_width = 0;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -682,25 +681,15 @@ static int mxs_mmc_probe(struct platform_device *pdev)
mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL;
- pdata = mmc_dev(host->mmc)->platform_data;
- if (!pdata) {
- u32 bus_width = 0;
- of_property_read_u32(np, "bus-width", &bus_width);
- if (bus_width == 4)
- mmc->caps |= MMC_CAP_4_BIT_DATA;
- else if (bus_width == 8)
- mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
- host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0,
- &flags);
- if (flags & OF_GPIO_ACTIVE_LOW)
- host->wp_inverted = 1;
- } else {
- if (pdata->flags & SLOTF_8_BIT_CAPABLE)
- mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
- if (pdata->flags & SLOTF_4_BIT_CAPABLE)
- mmc->caps |= MMC_CAP_4_BIT_DATA;
- host->wp_gpio = pdata->wp_gpio;
- }
+ of_property_read_u32(np, "bus-width", &bus_width);
+ if (bus_width == 4)
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+ else if (bus_width == 8)
+ mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
+ host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags);
+
+ if (flags & OF_GPIO_ACTIVE_LOW)
+ host->wp_inverted = 1;
mmc->f_min = 400000;
mmc->f_max = 288000000;
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index fedd258cc4ea..d0a912fbad3b 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -37,6 +37,7 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <mach/hardware.h>
#include <plat/mmc.h>
@@ -62,6 +63,7 @@
#define VS18 (1 << 26)
#define VS30 (1 << 25)
+#define HSS (1 << 21)
#define SDVS18 (0x5 << 9)
#define SDVS30 (0x6 << 9)
#define SDVS33 (0x7 << 9)
@@ -78,28 +80,17 @@
#define CLKD_SHIFT 6
#define DTO_MASK 0x000F0000
#define DTO_SHIFT 16
-#define INT_EN_MASK 0x307F0033
-#define BWR_ENABLE (1 << 4)
-#define BRR_ENABLE (1 << 5)
-#define DTO_ENABLE (1 << 20)
#define INIT_STREAM (1 << 1)
#define DP_SELECT (1 << 21)
#define DDIR (1 << 4)
-#define DMA_EN 0x1
+#define DMAE 0x1
#define MSBS (1 << 5)
#define BCE (1 << 1)
#define FOUR_BIT (1 << 1)
+#define HSPE (1 << 2)
#define DDR (1 << 19)
#define DW8 (1 << 5)
-#define CC 0x1
-#define TC 0x02
#define OD 0x1
-#define ERR (1 << 15)
-#define CMD_TIMEOUT (1 << 16)
-#define DATA_TIMEOUT (1 << 20)
-#define CMD_CRC (1 << 17)
-#define DATA_CRC (1 << 21)
-#define CARD_ERR (1 << 28)
#define STAT_CLEAR 0xFFFFFFFF
#define INIT_STREAM_CMD 0x00000000
#define DUAL_VOLT_OCR_BIT 7
@@ -108,6 +99,26 @@
#define SOFTRESET (1 << 1)
#define RESETDONE (1 << 0)
+/* Interrupt masks for IE and ISE register */
+#define CC_EN (1 << 0)
+#define TC_EN (1 << 1)
+#define BWR_EN (1 << 4)
+#define BRR_EN (1 << 5)
+#define ERR_EN (1 << 15)
+#define CTO_EN (1 << 16)
+#define CCRC_EN (1 << 17)
+#define CEB_EN (1 << 18)
+#define CIE_EN (1 << 19)
+#define DTO_EN (1 << 20)
+#define DCRC_EN (1 << 21)
+#define DEB_EN (1 << 22)
+#define CERR_EN (1 << 28)
+#define BADA_EN (1 << 29)
+
+#define INT_EN_MASK (BADA_EN | CERR_EN | DEB_EN | DCRC_EN |\
+ DTO_EN | CIE_EN | CEB_EN | CCRC_EN | CTO_EN | \
+ BRR_EN | BWR_EN | TC_EN | CC_EN)
+
#define MMC_AUTOSUSPEND_DELAY 100
#define MMC_TIMEOUT_MS 20
#define OMAP_MMC_MIN_CLOCK 400000
@@ -302,7 +313,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
reg = regulator_get(host->dev, "vmmc");
if (IS_ERR(reg)) {
- dev_dbg(host->dev, "vmmc regulator missing\n");
+ dev_err(host->dev, "vmmc regulator missing\n");
return PTR_ERR(reg);
} else {
mmc_slot(host).set_power = omap_hsmmc_set_power;
@@ -455,13 +466,13 @@ static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
unsigned int irq_mask;
if (host->use_dma)
- irq_mask = INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE);
+ irq_mask = INT_EN_MASK & ~(BRR_EN | BWR_EN);
else
irq_mask = INT_EN_MASK;
/* Disable timeout for erases */
if (cmd->opcode == MMC_ERASE)
- irq_mask &= ~DTO_ENABLE;
+ irq_mask &= ~DTO_EN;
OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
@@ -494,6 +505,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
struct mmc_ios *ios = &host->mmc->ios;
unsigned long regval;
unsigned long timeout;
+ unsigned long clkdiv;
dev_vdbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock);
@@ -501,7 +513,8 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
regval = OMAP_HSMMC_READ(host->base, SYSCTL);
regval = regval & ~(CLKD_MASK | DTO_MASK);
- regval = regval | (calc_divisor(host, ios) << 6) | (DTO << 16);
+ clkdiv = calc_divisor(host, ios);
+ regval = regval | (clkdiv << 6) | (DTO << 16);
OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
@@ -512,6 +525,27 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
&& time_before(jiffies, timeout))
cpu_relax();
+ /*
+ * Enable High-Speed Support
+ * Pre-Requisites
+ * - Controller should support High-Speed-Enable Bit
+ * - Controller should not be using DDR Mode
+ * - Controller should advertise that it supports High Speed
+ * in capabilities register
+ * - MMC/SD clock coming out of controller > 25MHz
+ */
+ if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) &&
+ (ios->timing != MMC_TIMING_UHS_DDR50) &&
+ ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
+ regval = OMAP_HSMMC_READ(host->base, HCTL);
+ if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
+ regval |= HSPE;
+ else
+ regval &= ~HSPE;
+
+ OMAP_HSMMC_WRITE(host->base, HCTL, regval);
+ }
+
omap_hsmmc_start_clock(host);
}
@@ -676,8 +710,8 @@ static void send_init_stream(struct omap_hsmmc_host *host)
OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
- while ((reg != CC) && time_before(jiffies, timeout))
- reg = OMAP_HSMMC_READ(host->base, STAT) & CC;
+ while ((reg != CC_EN) && time_before(jiffies, timeout))
+ reg = OMAP_HSMMC_READ(host->base, STAT) & CC_EN;
OMAP_HSMMC_WRITE(host->base, CON,
OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM);
@@ -768,7 +802,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
}
if (host->use_dma)
- cmdreg |= DMA_EN;
+ cmdreg |= DMAE;
host->req_in_progress = 1;
@@ -968,16 +1002,20 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
__func__);
}
-static void hsmmc_command_incomplete(struct omap_hsmmc_host *host, int err)
+static void hsmmc_command_incomplete(struct omap_hsmmc_host *host,
+ int err, int end_cmd)
{
- omap_hsmmc_reset_controller_fsm(host, SRC);
- host->cmd->error = err;
+ if (end_cmd) {
+ omap_hsmmc_reset_controller_fsm(host, SRC);
+ if (host->cmd)
+ host->cmd->error = err;
+ }
if (host->data) {
omap_hsmmc_reset_controller_fsm(host, SRD);
omap_hsmmc_dma_cleanup(host, err);
- }
-
+ } else if (host->mrq && host->mrq->cmd)
+ host->mrq->cmd->error = err;
}
static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
@@ -988,23 +1026,25 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
data = host->data;
dev_vdbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
- if (status & ERR) {
+ if (status & ERR_EN) {
omap_hsmmc_dbg_report_irq(host, status);
- if (status & (CMD_TIMEOUT | DATA_TIMEOUT))
- hsmmc_command_incomplete(host, -ETIMEDOUT);
- else if (status & (CMD_CRC | DATA_CRC))
- hsmmc_command_incomplete(host, -EILSEQ);
- end_cmd = 1;
+ if (status & (CTO_EN | CCRC_EN))
+ end_cmd = 1;
+ if (status & (CTO_EN | DTO_EN))
+ hsmmc_command_incomplete(host, -ETIMEDOUT, end_cmd);
+ else if (status & (CCRC_EN | DCRC_EN))
+ hsmmc_command_incomplete(host, -EILSEQ, end_cmd);
+
if (host->data || host->response_busy) {
- end_trans = 1;
+ end_trans = !end_cmd;
host->response_busy = 0;
}
}
- if (end_cmd || ((status & CC) && host->cmd))
+ if (end_cmd || ((status & CC_EN) && host->cmd))
omap_hsmmc_cmd_done(host, host->cmd);
- if ((end_trans || (status & TC)) && host->mrq)
+ if ((end_trans || (status & TC_EN)) && host->mrq)
omap_hsmmc_xfer_done(host, data);
}
@@ -1101,7 +1141,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
return 0;
err:
- dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage\n");
+ dev_err(mmc_dev(host->mmc), "Unable to switch operating voltage\n");
return ret;
}
@@ -1360,7 +1400,7 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
if (host->use_dma) {
ret = omap_hsmmc_start_dma_transfer(host, req);
if (ret != 0) {
- dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n");
+ dev_err(mmc_dev(host->mmc), "MMC start dma failure\n");
return ret;
}
}
@@ -1678,7 +1718,7 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
{
struct omap_mmc_platform_data *pdata;
struct device_node *np = dev->of_node;
- u32 bus_width;
+ u32 bus_width, max_freq;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
@@ -1705,6 +1745,12 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
if (of_find_property(np, "ti,needs-special-reset", NULL))
pdata->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
+ if (!of_property_read_u32(np, "max-frequency", &max_freq))
+ pdata->max_freq = max_freq;
+
+ if (of_find_property(np, "ti,needs-special-hs-handling", NULL))
+ pdata->slots[0].features |= HSMMC_HAS_HSPE_SUPPORT;
+
return pdata;
}
#else
@@ -1725,6 +1771,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
const struct of_device_id *match;
dma_cap_mask_t mask;
unsigned tx_req, rx_req;
+ struct pinctrl *pinctrl;
match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
if (match) {
@@ -1821,7 +1868,6 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
* MMC can still work without debounce clock.
*/
if (IS_ERR(host->dbclk)) {
- dev_warn(mmc_dev(host->mmc), "Failed to get debounce clk\n");
host->dbclk = NULL;
} else if (clk_prepare_enable(host->dbclk) != 0) {
dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n");
@@ -1889,13 +1935,13 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
ret = request_irq(host->irq, omap_hsmmc_irq, 0,
mmc_hostname(mmc), host);
if (ret) {
- dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
+ dev_err(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
goto err_irq;
}
if (pdata->init != NULL) {
if (pdata->init(&pdev->dev) != 0) {
- dev_dbg(mmc_dev(host->mmc),
+ dev_err(mmc_dev(host->mmc),
"Unable to configure MMC IRQs\n");
goto err_irq_cd_init;
}
@@ -1918,7 +1964,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
mmc_hostname(mmc), host);
if (ret) {
- dev_dbg(mmc_dev(host->mmc),
+ dev_err(mmc_dev(host->mmc),
"Unable to grab MMC CD IRQ\n");
goto err_irq_cd;
}
@@ -1928,6 +1974,11 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
omap_hsmmc_disable_irq(host);
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ dev_warn(&pdev->dev,
+ "pins are not configured from the driver\n");
+
omap_hsmmc_protect_card(host);
mmc_add_host(mmc);
@@ -2027,6 +2078,25 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
+static int omap_hsmmc_prepare(struct device *dev)
+{
+ struct omap_hsmmc_host *host = dev_get_drvdata(dev);
+
+ if (host->pdata->suspend)
+ return host->pdata->suspend(dev, host->slot_id);
+
+ return 0;
+}
+
+static void omap_hsmmc_complete(struct device *dev)
+{
+ struct omap_hsmmc_host *host = dev_get_drvdata(dev);
+
+ if (host->pdata->resume)
+ host->pdata->resume(dev, host->slot_id);
+
+}
+
static int omap_hsmmc_suspend(struct device *dev)
{
int ret = 0;
@@ -2040,23 +2110,10 @@ static int omap_hsmmc_suspend(struct device *dev)
pm_runtime_get_sync(host->dev);
host->suspended = 1;
- if (host->pdata->suspend) {
- ret = host->pdata->suspend(dev, host->slot_id);
- if (ret) {
- dev_dbg(dev, "Unable to handle MMC board"
- " level suspend\n");
- host->suspended = 0;
- return ret;
- }
- }
ret = mmc_suspend_host(host->mmc);
if (ret) {
host->suspended = 0;
- if (host->pdata->resume) {
- if (host->pdata->resume(dev, host->slot_id))
- dev_dbg(dev, "Unmask interrupt failed\n");
- }
goto err;
}
@@ -2093,12 +2150,6 @@ static int omap_hsmmc_resume(struct device *dev)
if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER))
omap_hsmmc_conf_bus_power(host);
- if (host->pdata->resume) {
- ret = host->pdata->resume(dev, host->slot_id);
- if (ret)
- dev_dbg(dev, "Unmask interrupt failed\n");
- }
-
omap_hsmmc_protect_card(host);
/* Notify the core to resume the host */
@@ -2114,8 +2165,10 @@ static int omap_hsmmc_resume(struct device *dev)
}
#else
+#define omap_hsmmc_prepare NULL
+#define omap_hsmmc_complete NULL
#define omap_hsmmc_suspend NULL
-#define omap_hsmmc_resume NULL
+#define omap_hsmmc_resume NULL
#endif
static int omap_hsmmc_runtime_suspend(struct device *dev)
@@ -2143,6 +2196,8 @@ static int omap_hsmmc_runtime_resume(struct device *dev)
static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
.suspend = omap_hsmmc_suspend,
.resume = omap_hsmmc_resume,
+ .prepare = omap_hsmmc_prepare,
+ .complete = omap_hsmmc_complete,
.runtime_suspend = omap_hsmmc_runtime_suspend,
.runtime_resume = omap_hsmmc_runtime_resume,
};
diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c
index 8fd50a211037..e6214480bc98 100644
--- a/drivers/mmc/host/sdhci-dove.c
+++ b/drivers/mmc/host/sdhci-dove.c
@@ -19,20 +19,30 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/err.h>
-#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
-#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
#include <linux/mmc/host.h>
+#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_gpio.h>
#include "sdhci-pltfm.h"
struct sdhci_dove_priv {
struct clk *clk;
+ int gpio_cd;
};
+static irqreturn_t sdhci_dove_carddetect_irq(int irq, void *data)
+{
+ struct sdhci_host *host = data;
+
+ tasklet_schedule(&host->card_tasklet);
+ return IRQ_HANDLED;
+}
+
static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
{
u16 ret;
@@ -50,16 +60,25 @@ static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)
{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_dove_priv *priv = pltfm_host->priv;
u32 ret;
+ ret = readl(host->ioaddr + reg);
+
switch (reg) {
case SDHCI_CAPABILITIES:
- ret = readl(host->ioaddr + reg);
/* Mask the support for 3.0V */
ret &= ~SDHCI_CAN_VDD_300;
break;
- default:
- ret = readl(host->ioaddr + reg);
+ case SDHCI_PRESENT_STATE:
+ if (gpio_is_valid(priv->gpio_cd)) {
+ if (gpio_get_value(priv->gpio_cd) == 0)
+ ret |= SDHCI_CARD_PRESENT;
+ else
+ ret &= ~SDHCI_CARD_PRESENT;
+ }
+ break;
}
return ret;
}
@@ -92,25 +111,70 @@ static int __devinit sdhci_dove_probe(struct platform_device *pdev)
return -ENOMEM;
}
- priv->clk = clk_get(&pdev->dev, NULL);
- if (!IS_ERR(priv->clk))
- clk_prepare_enable(priv->clk);
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
- ret = sdhci_pltfm_register(pdev, &sdhci_dove_pdata);
- if (ret)
- goto sdhci_dove_register_fail;
+ if (pdev->dev.of_node) {
+ priv->gpio_cd = of_get_named_gpio(pdev->dev.of_node,
+ "cd-gpios", 0);
+ } else {
+ priv->gpio_cd = -EINVAL;
+ }
+
+ if (gpio_is_valid(priv->gpio_cd)) {
+ ret = gpio_request(priv->gpio_cd, "sdhci-cd");
+ if (ret) {
+ dev_err(&pdev->dev, "card detect gpio request failed: %d\n",
+ ret);
+ return ret;
+ }
+ gpio_direction_input(priv->gpio_cd);
+ }
+
+ host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata);
+ if (IS_ERR(host)) {
+ ret = PTR_ERR(host);
+ goto err_sdhci_pltfm_init;
+ }
- host = platform_get_drvdata(pdev);
pltfm_host = sdhci_priv(host);
pltfm_host->priv = priv;
+ if (!IS_ERR(priv->clk))
+ clk_prepare_enable(priv->clk);
+
+ sdhci_get_of_property(pdev);
+
+ ret = sdhci_add_host(host);
+ if (ret)
+ goto err_sdhci_add;
+
+ /*
+ * We must request the IRQ after sdhci_add_host(), as the tasklet only
+ * gets setup in sdhci_add_host() and we oops.
+ */
+ if (gpio_is_valid(priv->gpio_cd)) {
+ ret = request_irq(gpio_to_irq(priv->gpio_cd),
+ sdhci_dove_carddetect_irq,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ mmc_hostname(host->mmc), host);
+ if (ret) {
+ dev_err(&pdev->dev, "card detect irq request failed: %d\n",
+ ret);
+ goto err_request_irq;
+ }
+ }
+
return 0;
-sdhci_dove_register_fail:
- if (!IS_ERR(priv->clk)) {
+err_request_irq:
+ sdhci_remove_host(host, 0);
+err_sdhci_add:
+ if (!IS_ERR(priv->clk))
clk_disable_unprepare(priv->clk);
- clk_put(priv->clk);
- }
+ sdhci_pltfm_free(pdev);
+err_sdhci_pltfm_init:
+ if (gpio_is_valid(priv->gpio_cd))
+ gpio_free(priv->gpio_cd);
return ret;
}
@@ -122,10 +186,14 @@ static int __devexit sdhci_dove_remove(struct platform_device *pdev)
sdhci_pltfm_unregister(pdev);
- if (!IS_ERR(priv->clk)) {
- clk_disable_unprepare(priv->clk);
- clk_put(priv->clk);
+ if (gpio_is_valid(priv->gpio_cd)) {
+ free_irq(gpio_to_irq(priv->gpio_cd), host);
+ gpio_free(priv->gpio_cd);
}
+
+ if (!IS_ERR(priv->clk))
+ clk_disable_unprepare(priv->clk);
+
return 0;
}
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index effc2acfe778..1849461c39ee 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -456,10 +456,10 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
pltfm_host = sdhci_priv(host);
- imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
+ imx_data = devm_kzalloc(&pdev->dev, sizeof(*imx_data), GFP_KERNEL);
if (!imx_data) {
err = -ENOMEM;
- goto err_imx_data;
+ goto free_sdhci;
}
if (of_id)
@@ -470,19 +470,19 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(imx_data->clk_ipg)) {
err = PTR_ERR(imx_data->clk_ipg);
- goto err_clk_get;
+ goto free_sdhci;
}
imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(imx_data->clk_ahb)) {
err = PTR_ERR(imx_data->clk_ahb);
- goto err_clk_get;
+ goto free_sdhci;
}
imx_data->clk_per = devm_clk_get(&pdev->dev, "per");
if (IS_ERR(imx_data->clk_per)) {
err = PTR_ERR(imx_data->clk_per);
- goto err_clk_get;
+ goto free_sdhci;
}
pltfm_host->clk = imx_data->clk_per;
@@ -494,7 +494,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(imx_data->pinctrl)) {
err = PTR_ERR(imx_data->pinctrl);
- goto pin_err;
+ goto disable_clk;
}
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
@@ -519,7 +519,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
if (!host->mmc->parent->platform_data) {
dev_err(mmc_dev(host->mmc), "no board data!\n");
err = -EINVAL;
- goto no_board_data;
+ goto disable_clk;
}
imx_data->boarddata = *((struct esdhc_platform_data *)
host->mmc->parent->platform_data);
@@ -527,7 +527,8 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
/* write_protect */
if (boarddata->wp_type == ESDHC_WP_GPIO) {
- err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
+ err = devm_gpio_request_one(&pdev->dev, boarddata->wp_gpio,
+ GPIOF_IN, "ESDHC_WP");
if (err) {
dev_warn(mmc_dev(host->mmc),
"no write-protect pin available!\n");
@@ -543,19 +544,21 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
switch (boarddata->cd_type) {
case ESDHC_CD_GPIO:
- err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD");
+ err = devm_gpio_request_one(&pdev->dev, boarddata->cd_gpio,
+ GPIOF_IN, "ESDHC_CD");
if (err) {
dev_err(mmc_dev(host->mmc),
"no card-detect pin available!\n");
- goto no_card_detect_pin;
+ goto disable_clk;
}
- err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq,
+ err = devm_request_irq(&pdev->dev,
+ gpio_to_irq(boarddata->cd_gpio), cd_irq,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
mmc_hostname(host->mmc), host);
if (err) {
dev_err(mmc_dev(host->mmc), "request irq error\n");
- goto no_card_detect_irq;
+ goto disable_clk;
}
/* fall through */
@@ -574,27 +577,15 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
err = sdhci_add_host(host);
if (err)
- goto err_add_host;
+ goto disable_clk;
return 0;
-err_add_host:
- if (gpio_is_valid(boarddata->cd_gpio))
- free_irq(gpio_to_irq(boarddata->cd_gpio), host);
-no_card_detect_irq:
- if (gpio_is_valid(boarddata->cd_gpio))
- gpio_free(boarddata->cd_gpio);
- if (gpio_is_valid(boarddata->wp_gpio))
- gpio_free(boarddata->wp_gpio);
-no_card_detect_pin:
-no_board_data:
-pin_err:
+disable_clk:
clk_disable_unprepare(imx_data->clk_per);
clk_disable_unprepare(imx_data->clk_ipg);
clk_disable_unprepare(imx_data->clk_ahb);
-err_clk_get:
- kfree(imx_data);
-err_imx_data:
+free_sdhci:
sdhci_pltfm_free(pdev);
return err;
}
@@ -604,25 +595,14 @@ static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv;
- struct esdhc_platform_data *boarddata = &imx_data->boarddata;
int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
sdhci_remove_host(host, dead);
- if (gpio_is_valid(boarddata->wp_gpio))
- gpio_free(boarddata->wp_gpio);
-
- if (gpio_is_valid(boarddata->cd_gpio)) {
- free_irq(gpio_to_irq(boarddata->cd_gpio), host);
- gpio_free(boarddata->cd_gpio);
- }
-
clk_disable_unprepare(imx_data->clk_per);
clk_disable_unprepare(imx_data->clk_ipg);
clk_disable_unprepare(imx_data->clk_ahb);
- kfree(imx_data);
-
sdhci_pltfm_free(pdev);
return 0;
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 63d219f57cae..60de2eeb39b1 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -22,6 +22,7 @@
#include "sdhci-esdhc.h"
#define VENDOR_V_22 0x12
+#define VENDOR_V_23 0x13
static u32 esdhc_readl(struct sdhci_host *host, int reg)
{
u32 ret;
@@ -85,6 +86,18 @@ static u8 esdhc_readb(struct sdhci_host *host, int reg)
return ret;
}
+static void esdhc_writel(struct sdhci_host *host, u32 val, int reg)
+{
+ /*
+ * Enable IRQSTATEN[BGESEN] is just to set IRQSTAT[BGE]
+ * when SYSCTL[RSTD]) is set for some special operations.
+ * No any impact other operation.
+ */
+ if (reg == SDHCI_INT_ENABLE)
+ val |= SDHCI_INT_BLK_GAP;
+ sdhci_be32bs_writel(host, val, reg);
+}
+
static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
{
if (reg == SDHCI_BLOCK_SIZE) {
@@ -121,6 +134,41 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
sdhci_be32bs_writeb(host, val, reg);
}
+/*
+ * For Abort or Suspend after Stop at Block Gap, ignore the ADMA
+ * error(IRQSTAT[ADMAE]) if both Transfer Complete(IRQSTAT[TC])
+ * and Block Gap Event(IRQSTAT[BGE]) are also set.
+ * For Continue, apply soft reset for data(SYSCTL[RSTD]);
+ * and re-issue the entire read transaction from beginning.
+ */
+static void esdhci_of_adma_workaround(struct sdhci_host *host, u32 intmask)
+{
+ u32 tmp;
+ bool applicable;
+ dma_addr_t dmastart;
+ dma_addr_t dmanow;
+
+ tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
+ tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
+
+ applicable = (intmask & SDHCI_INT_DATA_END) &&
+ (intmask & SDHCI_INT_BLK_GAP) &&
+ (tmp == VENDOR_V_23);
+ if (!applicable)
+ return;
+
+ host->data->error = 0;
+ dmastart = sg_dma_address(host->data->sg);
+ dmanow = dmastart + host->data->bytes_xfered;
+ /*
+ * Force update to the next DMA block boundary.
+ */
+ dmanow = (dmanow & ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
+ SDHCI_DEFAULT_BOUNDARY_SIZE;
+ host->data->bytes_xfered = dmanow - dmastart;
+ sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
+}
+
static int esdhc_of_enable_dma(struct sdhci_host *host)
{
setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
@@ -177,13 +225,16 @@ static void esdhc_of_platform_init(struct sdhci_host *host)
vvn = (vvn & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
if (vvn == VENDOR_V_22)
host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
+
+ if (vvn > VENDOR_V_22)
+ host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
}
static struct sdhci_ops sdhci_esdhc_ops = {
.read_l = esdhc_readl,
.read_w = esdhc_readw,
.read_b = esdhc_readb,
- .write_l = sdhci_be32bs_writel,
+ .write_l = esdhc_writel,
.write_w = esdhc_writew,
.write_b = esdhc_writeb,
.set_clock = esdhc_of_set_clock,
@@ -195,6 +246,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.platform_suspend = esdhc_of_suspend,
.platform_resume = esdhc_of_resume,
#endif
+ .adma_workaround = esdhci_of_adma_workaround,
};
static struct sdhci_pltfm_data sdhci_esdhc_pdata = {
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 04936f353ced..0777fad997ba 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -114,6 +114,7 @@ static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot)
SDHCI_TIMEOUT_CLK_UNIT |
SDHCI_CAN_VDD_330 |
+ SDHCI_CAN_DO_HISPD |
SDHCI_CAN_DO_SDMA;
return 0;
}
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index 27164457f861..d4283ef5917a 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -78,6 +78,9 @@ void sdhci_get_of_property(struct platform_device *pdev)
if (of_get_property(np, "broken-cd", NULL))
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+ if (of_get_property(np, "no-1-8-v", NULL))
+ host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
+
if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
@@ -89,6 +92,12 @@ void sdhci_get_of_property(struct platform_device *pdev)
clk = of_get_property(np, "clock-frequency", &size);
if (clk && size == sizeof(*clk) && *clk)
pltfm_host->clock = be32_to_cpup(clk);
+
+ if (of_find_property(np, "keep-power-in-suspend", NULL))
+ host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
+
+ if (of_find_property(np, "enable-sdio-wakeup", NULL))
+ host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
}
}
#else
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index e918a2bb3af1..60829c92bcfd 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -163,10 +163,18 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
return 0;
}
+static u32 pxav3_get_max_clock(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+ return clk_get_rate(pltfm_host->clk);
+}
+
static struct sdhci_ops pxav3_sdhci_ops = {
.platform_reset_exit = pxav3_set_private_registers,
.set_uhs_signaling = pxav3_set_uhs_signaling,
.platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
+ .get_max_clock = pxav3_get_max_clock,
};
#ifdef CONFIG_OF
@@ -249,7 +257,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
- | SDHCI_QUIRK_32BIT_ADMA_SIZE;
+ | SDHCI_QUIRK_32BIT_ADMA_SIZE
+ | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
/* enable 1/8V DDR capable */
host->mmc->caps |= MMC_CAP_1_8V_DDR;
@@ -271,6 +280,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
if (pdata->quirks)
host->quirks |= pdata->quirks;
+ if (pdata->quirks2)
+ host->quirks2 |= pdata->quirks2;
if (pdata->host_caps)
host->mmc->caps |= pdata->host_caps;
if (pdata->host_caps2)
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index a54dd5d7a5f9..82b7a7ad4217 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -24,6 +24,7 @@
#include <linux/of_gpio.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/mmc/host.h>
@@ -57,6 +58,7 @@ struct sdhci_s3c {
int ext_cd_irq;
int ext_cd_gpio;
int *gpios;
+ struct pinctrl *pctrl;
struct clk *clk_io;
struct clk *clk_bus[MAX_BUS_CLK];
@@ -373,18 +375,27 @@ static struct sdhci_ops sdhci_s3c_ops = {
static void sdhci_s3c_notify_change(struct platform_device *dev, int state)
{
struct sdhci_host *host = platform_get_drvdata(dev);
+#ifdef CONFIG_PM_RUNTIME
+ struct sdhci_s3c *sc = sdhci_priv(host);
+#endif
unsigned long flags;
if (host) {
spin_lock_irqsave(&host->lock, flags);
if (state) {
dev_dbg(&dev->dev, "card inserted.\n");
+#ifdef CONFIG_PM_RUNTIME
+ clk_prepare_enable(sc->clk_io);
+#endif
host->flags &= ~SDHCI_DEVICE_DEAD;
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
} else {
dev_dbg(&dev->dev, "card removed.\n");
host->flags |= SDHCI_DEVICE_DEAD;
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+#ifdef CONFIG_PM_RUNTIME
+ clk_disable_unprepare(sc->clk_io);
+#endif
}
tasklet_schedule(&host->card_tasklet);
spin_unlock_irqrestore(&host->lock, flags);
@@ -406,7 +417,7 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc)
struct s3c_sdhci_platdata *pdata = sc->pdata;
struct device *dev = &sc->pdev->dev;
- if (gpio_request(pdata->ext_cd_gpio, "SDHCI EXT CD") == 0) {
+ if (devm_gpio_request(dev, pdata->ext_cd_gpio, "SDHCI EXT CD") == 0) {
sc->ext_cd_gpio = pdata->ext_cd_gpio;
sc->ext_cd_irq = gpio_to_irq(pdata->ext_cd_gpio);
if (sc->ext_cd_irq &&
@@ -449,12 +460,12 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
return -ENOMEM;
/* get the card detection method */
- if (of_get_property(node, "broken-cd", 0)) {
+ if (of_get_property(node, "broken-cd", NULL)) {
pdata->cd_type = S3C_SDHCI_CD_NONE;
goto setup_bus;
}
- if (of_get_property(node, "non-removable", 0)) {
+ if (of_get_property(node, "non-removable", NULL)) {
pdata->cd_type = S3C_SDHCI_CD_PERMANENT;
goto setup_bus;
}
@@ -477,8 +488,9 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
return -EINVAL;
}
- dev_info(dev, "assuming no card detect line available\n");
- pdata->cd_type = S3C_SDHCI_CD_NONE;
+ /* assuming internal card detect that will be configured by pinctrl */
+ pdata->cd_type = S3C_SDHCI_CD_INTERNAL;
+ goto setup_bus;
found_cd:
if (pdata->cd_type == S3C_SDHCI_CD_GPIO) {
@@ -487,7 +499,7 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
if (of_get_property(node, "cd-inverted", NULL))
pdata->ext_cd_gpio_invert = 1;
} else if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
- ret = gpio_request(gpio, "sdhci-cd");
+ ret = devm_gpio_request(dev, gpio, "sdhci-cd");
if (ret) {
dev_err(dev, "card detect gpio request failed\n");
return -EINVAL;
@@ -496,33 +508,28 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
}
setup_bus:
+ if (!IS_ERR(ourhost->pctrl))
+ return 0;
+
/* get the gpios for command, clock and data lines */
for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) {
gpio = of_get_gpio(node, cnt);
if (!gpio_is_valid(gpio)) {
dev_err(dev, "invalid gpio[%d]\n", cnt);
- goto err_free_dt_cd_gpio;
+ return -EINVAL;
}
ourhost->gpios[cnt] = gpio;
}
for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) {
- ret = gpio_request(ourhost->gpios[cnt], "sdhci-gpio");
+ ret = devm_gpio_request(dev, ourhost->gpios[cnt], "sdhci-gpio");
if (ret) {
dev_err(dev, "gpio[%d] request failed\n", cnt);
- goto err_free_dt_gpios;
+ return -EINVAL;
}
}
return 0;
-
- err_free_dt_gpios:
- while (--cnt >= 0)
- gpio_free(ourhost->gpios[cnt]);
- err_free_dt_cd_gpio:
- if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL)
- gpio_free(ourhost->ext_cd_gpio);
- return -EINVAL;
}
#else
static int __devinit sdhci_s3c_parse_dt(struct device *dev,
@@ -579,13 +586,15 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
ret = -ENOMEM;
- goto err_pdata;
+ goto err_pdata_io_clk;
}
+ sc->pctrl = devm_pinctrl_get_select_default(&pdev->dev);
+
if (pdev->dev.of_node) {
ret = sdhci_s3c_parse_dt(&pdev->dev, host, pdata);
if (ret)
- goto err_pdata;
+ goto err_pdata_io_clk;
} else {
memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
sc->ext_cd_gpio = -1; /* invalid gpio number */
@@ -603,7 +612,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
if (IS_ERR(sc->clk_io)) {
dev_err(dev, "failed to get io clock\n");
ret = PTR_ERR(sc->clk_io);
- goto err_io_clk;
+ goto err_pdata_io_clk;
}
/* enable the local io clock and keep it running for the moment. */
@@ -766,13 +775,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
clk_disable_unprepare(sc->clk_io);
clk_put(sc->clk_io);
- err_io_clk:
- for (ptr = 0; ptr < NUM_GPIOS(sc->pdata->max_width); ptr++)
- gpio_free(sc->gpios[ptr]);
- if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL)
- gpio_free(sc->ext_cd_gpio);
-
- err_pdata:
+ err_pdata_io_clk:
sdhci_free_host(host);
return ret;
@@ -791,9 +794,6 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
if (sc->ext_cd_irq)
free_irq(sc->ext_cd_irq, sc);
- if (gpio_is_valid(sc->ext_cd_gpio))
- gpio_free(sc->ext_cd_gpio);
-
#ifdef CONFIG_PM_RUNTIME
if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL)
clk_prepare_enable(sc->clk_io);
@@ -814,11 +814,6 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
clk_disable_unprepare(sc->clk_io);
clk_put(sc->clk_io);
- if (pdev->dev.of_node) {
- for (ptr = 0; ptr < NUM_GPIOS(sc->pdata->max_width); ptr++)
- gpio_free(sc->gpios[ptr]);
- }
-
sdhci_free_host(host);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
index 6be89c032deb..87a700944b7d 100644
--- a/drivers/mmc/host/sdhci-spear.c
+++ b/drivers/mmc/host/sdhci-spear.c
@@ -146,6 +146,11 @@ static int __devinit sdhci_probe(struct platform_device *pdev)
goto put_clk;
}
+ ret = clk_set_rate(sdhci->clk, 50000000);
+ if (ret)
+ dev_dbg(&pdev->dev, "Error setting desired clk, clk=%lu\n",
+ clk_get_rate(sdhci->clk));
+
if (np) {
sdhci->data = sdhci_probe_config_dt(pdev);
if (IS_ERR(sdhci->data)) {
@@ -297,7 +302,7 @@ static int sdhci_suspend(struct device *dev)
ret = sdhci_suspend_host(host);
if (!ret)
- clk_disable_unprepare(sdhci->clk);
+ clk_disable(sdhci->clk);
return ret;
}
@@ -308,7 +313,7 @@ static int sdhci_resume(struct device *dev)
struct spear_sdhci *sdhci = dev_get_platdata(dev);
int ret;
- ret = clk_prepare_enable(sdhci->clk);
+ ret = clk_enable(sdhci->clk);
if (ret) {
dev_dbg(dev, "Resume: Error enabling clock\n");
return ret;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index c7851c0aabce..6f0bfc0c8c9c 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1618,7 +1618,7 @@ static int sdhci_do_3_3v_signal_voltage_switch(struct sdhci_host *host,
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
if (host->vqmmc) {
- ret = regulator_set_voltage(host->vqmmc, 3300000, 3300000);
+ ret = regulator_set_voltage(host->vqmmc, 2700000, 3600000);
if (ret) {
pr_warning("%s: Switching to 3.3V signalling voltage "
" failed\n", mmc_hostname(host->mmc));
@@ -1662,7 +1662,7 @@ static int sdhci_do_1_8v_signal_voltage_switch(struct sdhci_host *host,
*/
if (host->vqmmc)
ret = regulator_set_voltage(host->vqmmc,
- 1800000, 1800000);
+ 1700000, 1950000);
else
ret = 0;
@@ -1994,30 +1994,11 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
sdhci_runtime_pm_put(host);
}
-static const struct mmc_host_ops sdhci_ops = {
- .request = sdhci_request,
- .set_ios = sdhci_set_ios,
- .get_ro = sdhci_get_ro,
- .hw_reset = sdhci_hw_reset,
- .enable_sdio_irq = sdhci_enable_sdio_irq,
- .start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
- .execute_tuning = sdhci_execute_tuning,
- .enable_preset_value = sdhci_enable_preset_value,
-};
-
-/*****************************************************************************\
- * *
- * Tasklets *
- * *
-\*****************************************************************************/
-
-static void sdhci_tasklet_card(unsigned long param)
+static void sdhci_card_event(struct mmc_host *mmc)
{
- struct sdhci_host *host;
+ struct sdhci_host *host = mmc_priv(mmc);
unsigned long flags;
- host = (struct sdhci_host*)param;
-
spin_lock_irqsave(&host->lock, flags);
/* Check host->mrq first in case we are runtime suspended */
@@ -2036,6 +2017,31 @@ static void sdhci_tasklet_card(unsigned long param)
}
spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static const struct mmc_host_ops sdhci_ops = {
+ .request = sdhci_request,
+ .set_ios = sdhci_set_ios,
+ .get_ro = sdhci_get_ro,
+ .hw_reset = sdhci_hw_reset,
+ .enable_sdio_irq = sdhci_enable_sdio_irq,
+ .start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
+ .execute_tuning = sdhci_execute_tuning,
+ .enable_preset_value = sdhci_enable_preset_value,
+ .card_event = sdhci_card_event,
+};
+
+/*****************************************************************************\
+ * *
+ * Tasklets *
+ * *
+\*****************************************************************************/
+
+static void sdhci_tasklet_card(unsigned long param)
+{
+ struct sdhci_host *host = (struct sdhci_host*)param;
+
+ sdhci_card_event(host->mmc);
mmc_detect_change(host->mmc, msecs_to_jiffies(200));
}
@@ -2282,6 +2288,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
sdhci_show_adma_error(host);
host->data->error = -EIO;
+ if (host->ops->adma_workaround)
+ host->ops->adma_workaround(host, intmask);
}
if (host->data->error)
@@ -2858,10 +2866,16 @@ int sdhci_add_host(struct sdhci_host *host)
mmc_hostname(mmc));
host->vqmmc = NULL;
}
- }
- else if (regulator_is_supported_voltage(host->vqmmc, 1800000, 1800000))
+ } else {
regulator_enable(host->vqmmc);
- else
+ if (!regulator_is_supported_voltage(host->vqmmc, 1700000,
+ 1950000))
+ caps[1] &= ~(SDHCI_SUPPORT_SDR104 |
+ SDHCI_SUPPORT_SDR50 |
+ SDHCI_SUPPORT_DDR50);
+ }
+
+ if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)
caps[1] &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
SDHCI_SUPPORT_DDR50);
@@ -2919,21 +2933,18 @@ int sdhci_add_host(struct sdhci_host *host)
mmc_hostname(mmc));
host->vmmc = NULL;
}
- } else
- regulator_enable(host->vmmc);
+ }
#ifdef CONFIG_REGULATOR
if (host->vmmc) {
- ret = regulator_is_supported_voltage(host->vmmc, 3300000,
- 3300000);
+ ret = regulator_is_supported_voltage(host->vmmc, 2700000,
+ 3600000);
if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_330)))
caps[0] &= ~SDHCI_CAN_VDD_330;
- ret = regulator_is_supported_voltage(host->vmmc, 3000000,
- 3000000);
if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_300)))
caps[0] &= ~SDHCI_CAN_VDD_300;
- ret = regulator_is_supported_voltage(host->vmmc, 1800000,
- 1800000);
+ ret = regulator_is_supported_voltage(host->vmmc, 1700000,
+ 1950000);
if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_180)))
caps[0] &= ~SDHCI_CAN_VDD_180;
}
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 71a4a7ed46c5..a6d69b7bdea2 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -120,6 +120,7 @@
#define SDHCI_SIGNAL_ENABLE 0x38
#define SDHCI_INT_RESPONSE 0x00000001
#define SDHCI_INT_DATA_END 0x00000002
+#define SDHCI_INT_BLK_GAP 0x00000004
#define SDHCI_INT_DMA_END 0x00000008
#define SDHCI_INT_SPACE_AVAIL 0x00000010
#define SDHCI_INT_DATA_AVAIL 0x00000020
@@ -146,7 +147,8 @@
#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
- SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR)
+ SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \
+ SDHCI_INT_BLK_GAP)
#define SDHCI_INT_ALL_MASK ((unsigned int)-1)
#define SDHCI_ACMD12_ERR 0x3C
@@ -278,6 +280,7 @@ struct sdhci_ops {
void (*hw_reset)(struct sdhci_host *host);
void (*platform_suspend)(struct sdhci_host *host);
void (*platform_resume)(struct sdhci_host *host);
+ void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
void (*platform_init)(struct sdhci_host *host);
};
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index d25bc97dc5c6..ae795233a1d6 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -1104,7 +1104,6 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
{
struct sh_mmcif_host *host = dev_id;
struct mmc_request *mrq = host->mrq;
- struct mmc_data *data = mrq->data;
cancel_delayed_work_sync(&host->timeout_work);
@@ -1152,13 +1151,14 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
case MMCIF_WAIT_FOR_READ_END:
case MMCIF_WAIT_FOR_WRITE_END:
if (host->sd_error)
- data->error = sh_mmcif_error_manage(host);
+ mrq->data->error = sh_mmcif_error_manage(host);
break;
default:
BUG();
}
if (host->wait_for != MMCIF_WAIT_FOR_STOP) {
+ struct mmc_data *data = mrq->data;
if (!mrq->cmd->error && data && !data->error)
data->bytes_xfered =
data->blocks * data->blksz;
@@ -1231,10 +1231,6 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
host->sd_error = true;
dev_dbg(&host->pd->dev, "int err state = %08x\n", state);
}
- if (host->state == STATE_IDLE) {
- dev_info(&host->pd->dev, "Spurious IRQ status 0x%x", state);
- return IRQ_HANDLED;
- }
if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) {
if (!host->dma_active)
return IRQ_WAKE_THREAD;
@@ -1310,7 +1306,6 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
struct sh_mmcif_plat_data *pd = pdev->dev.platform_data;
struct resource *res;
void __iomem *reg;
- char clk_name[8];
irq[0] = platform_get_irq(pdev, 0);
irq[1] = platform_get_irq(pdev, 1);
@@ -1360,11 +1355,10 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
host->power = false;
- snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id);
- host->hclk = clk_get(&pdev->dev, clk_name);
+ host->hclk = clk_get(&pdev->dev, NULL);
if (IS_ERR(host->hclk)) {
ret = PTR_ERR(host->hclk);
- dev_err(&pdev->dev, "cannot get clock \"%s\": %d\n", clk_name, ret);
+ dev_err(&pdev->dev, "cannot get clock: %d\n", ret);
goto eclkget;
}
ret = sh_mmcif_clk_update(host);
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 0bdc146178db..d6ff8531fb35 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -123,7 +123,6 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
struct tmio_mmc_data *mmc_data;
struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
struct tmio_mmc_host *host;
- char clk_name[8];
int irq, ret, i = 0;
bool multiplexed_isr = true;
@@ -144,11 +143,10 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
}
}
- snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
- priv->clk = clk_get(&pdev->dev, clk_name);
+ priv->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(priv->clk)) {
- dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
ret = PTR_ERR(priv->clk);
+ dev_err(&pdev->dev, "cannot get clock: %d\n", ret);
goto eclkget;
}
@@ -250,7 +248,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
mmc_hostname(host->mmc), (unsigned long)
(platform_get_resource(pdev, IORESOURCE_MEM, 0)->start),
- mmc_data->hclk / 1000000);
+ host->mmc->f_max / 1000000);
return ret;
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index d5655a63eda4..cb9f361c03ab 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -2362,6 +2362,7 @@ error4:
error1:
usb_free_urb(command_out_urb);
error0:
+ usb_put_dev(udev);
return retval;
}
diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c
new file mode 100644
index 000000000000..5ba4605e4f80
--- /dev/null
+++ b/drivers/mmc/host/wmt-sdmmc.c
@@ -0,0 +1,1029 @@
+/*
+ * WM8505/WM8650 SD/MMC Host Controller
+ *
+ * Copyright (C) 2010 Tony Prisk
+ * Copyright (C) 2008 WonderMedia Technologies, Inc.
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+
+#include <asm/byteorder.h>
+
+
+#define DRIVER_NAME "wmt-sdhc"
+
+
+/* MMC/SD controller registers */
+#define SDMMC_CTLR 0x00
+#define SDMMC_CMD 0x01
+#define SDMMC_RSPTYPE 0x02
+#define SDMMC_ARG 0x04
+#define SDMMC_BUSMODE 0x08
+#define SDMMC_BLKLEN 0x0C
+#define SDMMC_BLKCNT 0x0E
+#define SDMMC_RSP 0x10
+#define SDMMC_CBCR 0x20
+#define SDMMC_INTMASK0 0x24
+#define SDMMC_INTMASK1 0x25
+#define SDMMC_STS0 0x28
+#define SDMMC_STS1 0x29
+#define SDMMC_STS2 0x2A
+#define SDMMC_STS3 0x2B
+#define SDMMC_RSPTIMEOUT 0x2C
+#define SDMMC_CLK 0x30 /* VT8500 only */
+#define SDMMC_EXTCTRL 0x34
+#define SDMMC_SBLKLEN 0x38
+#define SDMMC_DMATIMEOUT 0x3C
+
+
+/* SDMMC_CTLR bit fields */
+#define CTLR_CMD_START 0x01
+#define CTLR_CMD_WRITE 0x04
+#define CTLR_FIFO_RESET 0x08
+
+/* SDMMC_BUSMODE bit fields */
+#define BM_SPI_MODE 0x01
+#define BM_FOURBIT_MODE 0x02
+#define BM_EIGHTBIT_MODE 0x04
+#define BM_SD_OFF 0x10
+#define BM_SPI_CS 0x20
+#define BM_SD_POWER 0x40
+#define BM_SOFT_RESET 0x80
+#define BM_ONEBIT_MASK 0xFD
+
+/* SDMMC_BLKLEN bit fields */
+#define BLKL_CRCERR_ABORT 0x0800
+#define BLKL_CD_POL_HIGH 0x1000
+#define BLKL_GPI_CD 0x2000
+#define BLKL_DATA3_CD 0x4000
+#define BLKL_INT_ENABLE 0x8000
+
+/* SDMMC_INTMASK0 bit fields */
+#define INT0_MBLK_TRAN_DONE_INT_EN 0x10
+#define INT0_BLK_TRAN_DONE_INT_EN 0x20
+#define INT0_CD_INT_EN 0x40
+#define INT0_DI_INT_EN 0x80
+
+/* SDMMC_INTMASK1 bit fields */
+#define INT1_CMD_RES_TRAN_DONE_INT_EN 0x02
+#define INT1_CMD_RES_TOUT_INT_EN 0x04
+#define INT1_MBLK_AUTO_STOP_INT_EN 0x08
+#define INT1_DATA_TOUT_INT_EN 0x10
+#define INT1_RESCRC_ERR_INT_EN 0x20
+#define INT1_RCRC_ERR_INT_EN 0x40
+#define INT1_WCRC_ERR_INT_EN 0x80
+
+/* SDMMC_STS0 bit fields */
+#define STS0_WRITE_PROTECT 0x02
+#define STS0_CD_DATA3 0x04
+#define STS0_CD_GPI 0x08
+#define STS0_MBLK_DONE 0x10
+#define STS0_BLK_DONE 0x20
+#define STS0_CARD_DETECT 0x40
+#define STS0_DEVICE_INS 0x80
+
+/* SDMMC_STS1 bit fields */
+#define STS1_SDIO_INT 0x01
+#define STS1_CMDRSP_DONE 0x02
+#define STS1_RSP_TIMEOUT 0x04
+#define STS1_AUTOSTOP_DONE 0x08
+#define STS1_DATA_TIMEOUT 0x10
+#define STS1_RSP_CRC_ERR 0x20
+#define STS1_RCRC_ERR 0x40
+#define STS1_WCRC_ERR 0x80
+
+/* SDMMC_STS2 bit fields */
+#define STS2_CMD_RES_BUSY 0x10
+#define STS2_DATARSP_BUSY 0x20
+#define STS2_DIS_FORCECLK 0x80
+
+
+/* MMC/SD DMA Controller Registers */
+#define SDDMA_GCR 0x100
+#define SDDMA_IER 0x104
+#define SDDMA_ISR 0x108
+#define SDDMA_DESPR 0x10C
+#define SDDMA_RBR 0x110
+#define SDDMA_DAR 0x114
+#define SDDMA_BAR 0x118
+#define SDDMA_CPR 0x11C
+#define SDDMA_CCR 0x120
+
+
+/* SDDMA_GCR bit fields */
+#define DMA_GCR_DMA_EN 0x00000001
+#define DMA_GCR_SOFT_RESET 0x00000100
+
+/* SDDMA_IER bit fields */
+#define DMA_IER_INT_EN 0x00000001
+
+/* SDDMA_ISR bit fields */
+#define DMA_ISR_INT_STS 0x00000001
+
+/* SDDMA_RBR bit fields */
+#define DMA_RBR_FORMAT 0x40000000
+#define DMA_RBR_END 0x80000000
+
+/* SDDMA_CCR bit fields */
+#define DMA_CCR_RUN 0x00000080
+#define DMA_CCR_IF_TO_PERIPHERAL 0x00000000
+#define DMA_CCR_PERIPHERAL_TO_IF 0x00400000
+
+/* SDDMA_CCR event status */
+#define DMA_CCR_EVT_NO_STATUS 0x00000000
+#define DMA_CCR_EVT_UNDERRUN 0x00000001
+#define DMA_CCR_EVT_OVERRUN 0x00000002
+#define DMA_CCR_EVT_DESP_READ 0x00000003
+#define DMA_CCR_EVT_DATA_RW 0x00000004
+#define DMA_CCR_EVT_EARLY_END 0x00000005
+#define DMA_CCR_EVT_SUCCESS 0x0000000F
+
+#define PDMA_READ 0x00
+#define PDMA_WRITE 0x01
+
+#define WMT_SD_POWER_OFF 0
+#define WMT_SD_POWER_ON 1
+
+struct wmt_dma_descriptor {
+ u32 flags;
+ u32 data_buffer_addr;
+ u32 branch_addr;
+ u32 reserved1;
+};
+
+struct wmt_mci_caps {
+ unsigned int f_min;
+ unsigned int f_max;
+ u32 ocr_avail;
+ u32 caps;
+ u32 max_seg_size;
+ u32 max_segs;
+ u32 max_blk_size;
+};
+
+struct wmt_mci_priv {
+ struct mmc_host *mmc;
+ void __iomem *sdmmc_base;
+
+ int irq_regular;
+ int irq_dma;
+
+ void *dma_desc_buffer;
+ dma_addr_t dma_desc_device_addr;
+
+ struct completion cmdcomp;
+ struct completion datacomp;
+
+ struct completion *comp_cmd;
+ struct completion *comp_dma;
+
+ struct mmc_request *req;
+ struct mmc_command *cmd;
+
+ struct clk *clk_sdmmc;
+ struct device *dev;
+
+ u8 power_inverted;
+ u8 cd_inverted;
+};
+
+static void wmt_set_sd_power(struct wmt_mci_priv *priv, int enable)
+{
+ u32 reg_tmp;
+ if (enable) {
+ if (priv->power_inverted) {
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp | BM_SD_OFF,
+ priv->sdmmc_base + SDMMC_BUSMODE);
+ } else {
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp & (~BM_SD_OFF),
+ priv->sdmmc_base + SDMMC_BUSMODE);
+ }
+ } else {
+ if (priv->power_inverted) {
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp & (~BM_SD_OFF),
+ priv->sdmmc_base + SDMMC_BUSMODE);
+ } else {
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp | BM_SD_OFF,
+ priv->sdmmc_base + SDMMC_BUSMODE);
+ }
+ }
+}
+
+static void wmt_mci_read_response(struct mmc_host *mmc)
+{
+ struct wmt_mci_priv *priv;
+ int idx1, idx2;
+ u8 tmp_resp;
+ u32 response;
+
+ priv = mmc_priv(mmc);
+
+ for (idx1 = 0; idx1 < 4; idx1++) {
+ response = 0;
+ for (idx2 = 0; idx2 < 4; idx2++) {
+ if ((idx1 == 3) && (idx2 == 3))
+ tmp_resp = readb(priv->sdmmc_base + SDMMC_RSP);
+ else
+ tmp_resp = readb(priv->sdmmc_base + SDMMC_RSP +
+ (idx1*4) + idx2 + 1);
+ response |= (tmp_resp << (idx2 * 8));
+ }
+ priv->cmd->resp[idx1] = cpu_to_be32(response);
+ }
+}
+
+static void wmt_mci_start_command(struct wmt_mci_priv *priv)
+{
+ u32 reg_tmp;
+
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR);
+ writeb(reg_tmp | CTLR_CMD_START, priv->sdmmc_base + SDMMC_CTLR);
+}
+
+static int wmt_mci_send_command(struct mmc_host *mmc, u8 command, u8 cmdtype,
+ u32 arg, u8 rsptype)
+{
+ struct wmt_mci_priv *priv;
+ u32 reg_tmp;
+
+ priv = mmc_priv(mmc);
+
+ /* write command, arg, resptype registers */
+ writeb(command, priv->sdmmc_base + SDMMC_CMD);
+ writel(arg, priv->sdmmc_base + SDMMC_ARG);
+ writeb(rsptype, priv->sdmmc_base + SDMMC_RSPTYPE);
+
+ /* reset response FIFO */
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR);
+ writeb(reg_tmp | CTLR_FIFO_RESET, priv->sdmmc_base + SDMMC_CTLR);
+
+ /* ensure clock enabled - VT3465 */
+ wmt_set_sd_power(priv, WMT_SD_POWER_ON);
+
+ /* clear status bits */
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS0);
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS1);
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS2);
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS3);
+
+ /* set command type */
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR);
+ writeb((reg_tmp & 0x0F) | (cmdtype << 4),
+ priv->sdmmc_base + SDMMC_CTLR);
+
+ return 0;
+}
+
+static void wmt_mci_disable_dma(struct wmt_mci_priv *priv)
+{
+ writel(DMA_ISR_INT_STS, priv->sdmmc_base + SDDMA_ISR);
+ writel(0, priv->sdmmc_base + SDDMA_IER);
+}
+
+static void wmt_complete_data_request(struct wmt_mci_priv *priv)
+{
+ struct mmc_request *req;
+ req = priv->req;
+
+ req->data->bytes_xfered = req->data->blksz * req->data->blocks;
+
+ /* unmap the DMA pages used for write data */
+ if (req->data->flags & MMC_DATA_WRITE)
+ dma_unmap_sg(mmc_dev(priv->mmc), req->data->sg,
+ req->data->sg_len, DMA_TO_DEVICE);
+ else
+ dma_unmap_sg(mmc_dev(priv->mmc), req->data->sg,
+ req->data->sg_len, DMA_FROM_DEVICE);
+
+ /* Check if the DMA ISR returned a data error */
+ if ((req->cmd->error) || (req->data->error))
+ mmc_request_done(priv->mmc, req);
+ else {
+ wmt_mci_read_response(priv->mmc);
+ if (!req->data->stop) {
+ /* single-block read/write requests end here */
+ mmc_request_done(priv->mmc, req);
+ } else {
+ /*
+ * we change the priv->cmd variable so the response is
+ * stored in the stop struct rather than the original
+ * calling command struct
+ */
+ priv->comp_cmd = &priv->cmdcomp;
+ init_completion(priv->comp_cmd);
+ priv->cmd = req->data->stop;
+ wmt_mci_send_command(priv->mmc, req->data->stop->opcode,
+ 7, req->data->stop->arg, 9);
+ wmt_mci_start_command(priv);
+ }
+ }
+}
+
+static irqreturn_t wmt_mci_dma_isr(int irq_num, void *data)
+{
+ struct mmc_host *mmc;
+ struct wmt_mci_priv *priv;
+
+ int status;
+
+ priv = (struct wmt_mci_priv *)data;
+ mmc = priv->mmc;
+
+ status = readl(priv->sdmmc_base + SDDMA_CCR) & 0x0F;
+
+ if (status != DMA_CCR_EVT_SUCCESS) {
+ dev_err(priv->dev, "DMA Error: Status = %d\n", status);
+ priv->req->data->error = -ETIMEDOUT;
+ complete(priv->comp_dma);
+ return IRQ_HANDLED;
+ }
+
+ priv->req->data->error = 0;
+
+ wmt_mci_disable_dma(priv);
+
+ complete(priv->comp_dma);
+
+ if (priv->comp_cmd) {
+ if (completion_done(priv->comp_cmd)) {
+ /*
+ * if the command (regular) interrupt has already
+ * completed, finish off the request otherwise we wait
+ * for the command interrupt and finish from there.
+ */
+ wmt_complete_data_request(priv);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wmt_mci_regular_isr(int irq_num, void *data)
+{
+ struct wmt_mci_priv *priv;
+ u32 status0;
+ u32 status1;
+ u32 status2;
+ u32 reg_tmp;
+ int cmd_done;
+
+ priv = (struct wmt_mci_priv *)data;
+ cmd_done = 0;
+ status0 = readb(priv->sdmmc_base + SDMMC_STS0);
+ status1 = readb(priv->sdmmc_base + SDMMC_STS1);
+ status2 = readb(priv->sdmmc_base + SDMMC_STS2);
+
+ /* Check for card insertion */
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_INTMASK0);
+ if ((reg_tmp & INT0_DI_INT_EN) && (status0 & STS0_DEVICE_INS)) {
+ mmc_detect_change(priv->mmc, 0);
+ if (priv->cmd)
+ priv->cmd->error = -ETIMEDOUT;
+ if (priv->comp_cmd)
+ complete(priv->comp_cmd);
+ if (priv->comp_dma) {
+ wmt_mci_disable_dma(priv);
+ complete(priv->comp_dma);
+ }
+ writeb(STS0_DEVICE_INS, priv->sdmmc_base + SDMMC_STS0);
+ return IRQ_HANDLED;
+ }
+
+ if ((!priv->req->data) ||
+ ((priv->req->data->stop) && (priv->cmd == priv->req->data->stop))) {
+ /* handle non-data & stop_transmission requests */
+ if (status1 & STS1_CMDRSP_DONE) {
+ priv->cmd->error = 0;
+ cmd_done = 1;
+ } else if ((status1 & STS1_RSP_TIMEOUT) ||
+ (status1 & STS1_DATA_TIMEOUT)) {
+ priv->cmd->error = -ETIMEDOUT;
+ cmd_done = 1;
+ }
+
+ if (cmd_done) {
+ priv->comp_cmd = NULL;
+
+ if (!priv->cmd->error)
+ wmt_mci_read_response(priv->mmc);
+
+ priv->cmd = NULL;
+
+ mmc_request_done(priv->mmc, priv->req);
+ }
+ } else {
+ /* handle data requests */
+ if (status1 & STS1_CMDRSP_DONE) {
+ if (priv->cmd)
+ priv->cmd->error = 0;
+ if (priv->comp_cmd)
+ complete(priv->comp_cmd);
+ }
+
+ if ((status1 & STS1_RSP_TIMEOUT) ||
+ (status1 & STS1_DATA_TIMEOUT)) {
+ if (priv->cmd)
+ priv->cmd->error = -ETIMEDOUT;
+ if (priv->comp_cmd)
+ complete(priv->comp_cmd);
+ if (priv->comp_dma) {
+ wmt_mci_disable_dma(priv);
+ complete(priv->comp_dma);
+ }
+ }
+
+ if (priv->comp_dma) {
+ /*
+ * If the dma interrupt has already completed, finish
+ * off the request; otherwise we wait for the DMA
+ * interrupt and finish from there.
+ */
+ if (completion_done(priv->comp_dma))
+ wmt_complete_data_request(priv);
+ }
+ }
+
+ writeb(status0, priv->sdmmc_base + SDMMC_STS0);
+ writeb(status1, priv->sdmmc_base + SDMMC_STS1);
+ writeb(status2, priv->sdmmc_base + SDMMC_STS2);
+
+ return IRQ_HANDLED;
+}
+
+static void wmt_reset_hardware(struct mmc_host *mmc)
+{
+ struct wmt_mci_priv *priv;
+ u32 reg_tmp;
+
+ priv = mmc_priv(mmc);
+
+ /* reset controller */
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + SDMMC_BUSMODE);
+
+ /* reset response FIFO */
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR);
+ writeb(reg_tmp | CTLR_FIFO_RESET, priv->sdmmc_base + SDMMC_CTLR);
+
+ /* enable GPI pin to detect card */
+ writew(BLKL_INT_ENABLE | BLKL_GPI_CD, priv->sdmmc_base + SDMMC_BLKLEN);
+
+ /* clear interrupt status */
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS0);
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS1);
+
+ /* setup interrupts */
+ writeb(INT0_CD_INT_EN | INT0_DI_INT_EN, priv->sdmmc_base +
+ SDMMC_INTMASK0);
+ writeb(INT1_DATA_TOUT_INT_EN | INT1_CMD_RES_TRAN_DONE_INT_EN |
+ INT1_CMD_RES_TOUT_INT_EN, priv->sdmmc_base + SDMMC_INTMASK1);
+
+ /* set the DMA timeout */
+ writew(8191, priv->sdmmc_base + SDMMC_DMATIMEOUT);
+
+ /* auto clock freezing enable */
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_STS2);
+ writeb(reg_tmp | STS2_DIS_FORCECLK, priv->sdmmc_base + SDMMC_STS2);
+
+ /* set a default clock speed of 400Khz */
+ clk_set_rate(priv->clk_sdmmc, 400000);
+}
+
+static int wmt_dma_init(struct mmc_host *mmc)
+{
+ struct wmt_mci_priv *priv;
+
+ priv = mmc_priv(mmc);
+
+ writel(DMA_GCR_SOFT_RESET, priv->sdmmc_base + SDDMA_GCR);
+ writel(DMA_GCR_DMA_EN, priv->sdmmc_base + SDDMA_GCR);
+ if ((readl(priv->sdmmc_base + SDDMA_GCR) & DMA_GCR_DMA_EN) != 0)
+ return 0;
+ else
+ return 1;
+}
+
+static void wmt_dma_init_descriptor(struct wmt_dma_descriptor *desc,
+ u16 req_count, u32 buffer_addr, u32 branch_addr, int end)
+{
+ desc->flags = 0x40000000 | req_count;
+ if (end)
+ desc->flags |= 0x80000000;
+ desc->data_buffer_addr = buffer_addr;
+ desc->branch_addr = branch_addr;
+}
+
+static void wmt_dma_config(struct mmc_host *mmc, u32 descaddr, u8 dir)
+{
+ struct wmt_mci_priv *priv;
+ u32 reg_tmp;
+
+ priv = mmc_priv(mmc);
+
+ /* Enable DMA Interrupts */
+ writel(DMA_IER_INT_EN, priv->sdmmc_base + SDDMA_IER);
+
+ /* Write DMA Descriptor Pointer Register */
+ writel(descaddr, priv->sdmmc_base + SDDMA_DESPR);
+
+ writel(0x00, priv->sdmmc_base + SDDMA_CCR);
+
+ if (dir == PDMA_WRITE) {
+ reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR);
+ writel(reg_tmp & DMA_CCR_IF_TO_PERIPHERAL, priv->sdmmc_base +
+ SDDMA_CCR);
+ } else {
+ reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR);
+ writel(reg_tmp | DMA_CCR_PERIPHERAL_TO_IF, priv->sdmmc_base +
+ SDDMA_CCR);
+ }
+}
+
+static void wmt_dma_start(struct wmt_mci_priv *priv)
+{
+ u32 reg_tmp;
+
+ reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR);
+ writel(reg_tmp | DMA_CCR_RUN, priv->sdmmc_base + SDDMA_CCR);
+}
+
+static void wmt_mci_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+ struct wmt_mci_priv *priv;
+ struct wmt_dma_descriptor *desc;
+ u8 command;
+ u8 cmdtype;
+ u32 arg;
+ u8 rsptype;
+ u32 reg_tmp;
+
+ struct scatterlist *sg;
+ int i;
+ int sg_cnt;
+ int offset;
+ u32 dma_address;
+ int desc_cnt;
+
+ priv = mmc_priv(mmc);
+ priv->req = req;
+
+ /*
+ * Use the cmd variable to pass a pointer to the resp[] structure
+ * This is required on multi-block requests to pass the pointer to the
+ * stop command
+ */
+ priv->cmd = req->cmd;
+
+ command = req->cmd->opcode;
+ arg = req->cmd->arg;
+ rsptype = mmc_resp_type(req->cmd);
+ cmdtype = 0;
+
+ /* rsptype=7 only valid for SPI commands - should be =2 for SD */
+ if (rsptype == 7)
+ rsptype = 2;
+ /* rsptype=21 is R1B, convert for controller */
+ if (rsptype == 21)
+ rsptype = 9;
+
+ if (!req->data) {
+ wmt_mci_send_command(mmc, command, cmdtype, arg, rsptype);
+ wmt_mci_start_command(priv);
+ /* completion is now handled in the regular_isr() */
+ }
+ if (req->data) {
+ priv->comp_cmd = &priv->cmdcomp;
+ init_completion(priv->comp_cmd);
+
+ wmt_dma_init(mmc);
+
+ /* set controller data length */
+ reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN);
+ writew((reg_tmp & 0xF800) | (req->data->blksz - 1),
+ priv->sdmmc_base + SDMMC_BLKLEN);
+
+ /* set controller block count */
+ writew(req->data->blocks, priv->sdmmc_base + SDMMC_BLKCNT);
+
+ desc = (struct wmt_dma_descriptor *)priv->dma_desc_buffer;
+
+ if (req->data->flags & MMC_DATA_WRITE) {
+ sg_cnt = dma_map_sg(mmc_dev(mmc), req->data->sg,
+ req->data->sg_len, DMA_TO_DEVICE);
+ cmdtype = 1;
+ if (req->data->blocks > 1)
+ cmdtype = 3;
+ } else {
+ sg_cnt = dma_map_sg(mmc_dev(mmc), req->data->sg,
+ req->data->sg_len, DMA_FROM_DEVICE);
+ cmdtype = 2;
+ if (req->data->blocks > 1)
+ cmdtype = 4;
+ }
+
+ dma_address = priv->dma_desc_device_addr + 16;
+ desc_cnt = 0;
+
+ for_each_sg(req->data->sg, sg, sg_cnt, i) {
+ offset = 0;
+ while (offset < sg_dma_len(sg)) {
+ wmt_dma_init_descriptor(desc, req->data->blksz,
+ sg_dma_address(sg)+offset,
+ dma_address, 0);
+ desc++;
+ desc_cnt++;
+ offset += req->data->blksz;
+ dma_address += 16;
+ if (desc_cnt == req->data->blocks)
+ break;
+ }
+ }
+ desc--;
+ desc->flags |= 0x80000000;
+
+ if (req->data->flags & MMC_DATA_WRITE)
+ wmt_dma_config(mmc, priv->dma_desc_device_addr,
+ PDMA_WRITE);
+ else
+ wmt_dma_config(mmc, priv->dma_desc_device_addr,
+ PDMA_READ);
+
+ wmt_mci_send_command(mmc, command, cmdtype, arg, rsptype);
+
+ priv->comp_dma = &priv->datacomp;
+ init_completion(priv->comp_dma);
+
+ wmt_dma_start(priv);
+ wmt_mci_start_command(priv);
+ }
+}
+
+static void wmt_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct wmt_mci_priv *priv;
+ u32 reg_tmp;
+
+ priv = mmc_priv(mmc);
+
+ if (ios->power_mode == MMC_POWER_UP) {
+ wmt_reset_hardware(mmc);
+
+ wmt_set_sd_power(priv, WMT_SD_POWER_ON);
+ }
+ if (ios->power_mode == MMC_POWER_OFF)
+ wmt_set_sd_power(priv, WMT_SD_POWER_OFF);
+
+ if (ios->clock != 0)
+ clk_set_rate(priv->clk_sdmmc, ios->clock);
+
+ switch (ios->bus_width) {
+ case MMC_BUS_WIDTH_8:
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL);
+ writeb(reg_tmp | 0x04, priv->sdmmc_base + SDMMC_EXTCTRL);
+ break;
+ case MMC_BUS_WIDTH_4:
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp | BM_FOURBIT_MODE, priv->sdmmc_base +
+ SDMMC_BUSMODE);
+
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL);
+ writeb(reg_tmp & 0xFB, priv->sdmmc_base + SDMMC_EXTCTRL);
+ break;
+ case MMC_BUS_WIDTH_1:
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp & BM_ONEBIT_MASK, priv->sdmmc_base +
+ SDMMC_BUSMODE);
+
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL);
+ writeb(reg_tmp & 0xFB, priv->sdmmc_base + SDMMC_EXTCTRL);
+ break;
+ }
+}
+
+static int wmt_mci_get_ro(struct mmc_host *mmc)
+{
+ struct wmt_mci_priv *priv = mmc_priv(mmc);
+
+ return !(readb(priv->sdmmc_base + SDMMC_STS0) & STS0_WRITE_PROTECT);
+}
+
+static int wmt_mci_get_cd(struct mmc_host *mmc)
+{
+ struct wmt_mci_priv *priv = mmc_priv(mmc);
+ u32 cd = (readb(priv->sdmmc_base + SDMMC_STS0) & STS0_CD_GPI) >> 3;
+
+ return !(cd ^ priv->cd_inverted);
+}
+
+static struct mmc_host_ops wmt_mci_ops = {
+ .request = wmt_mci_request,
+ .set_ios = wmt_mci_set_ios,
+ .get_ro = wmt_mci_get_ro,
+ .get_cd = wmt_mci_get_cd,
+};
+
+/* Controller capabilities */
+static struct wmt_mci_caps wm8505_caps = {
+ .f_min = 390425,
+ .f_max = 50000000,
+ .ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED |
+ MMC_CAP_SD_HIGHSPEED,
+ .max_seg_size = 65024,
+ .max_segs = 128,
+ .max_blk_size = 2048,
+};
+
+static struct of_device_id wmt_mci_dt_ids[] = {
+ { .compatible = "wm,wm8505-sdhc", .data = &wm8505_caps },
+ { /* Sentinel */ },
+};
+
+static int __devinit wmt_mci_probe(struct platform_device *pdev)
+{
+ struct mmc_host *mmc;
+ struct wmt_mci_priv *priv;
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *of_id =
+ of_match_device(wmt_mci_dt_ids, &pdev->dev);
+ const struct wmt_mci_caps *wmt_caps = of_id->data;
+ int ret;
+ int regular_irq, dma_irq;
+
+ if (!of_id || !of_id->data) {
+ dev_err(&pdev->dev, "Controller capabilities data missing\n");
+ return -EFAULT;
+ }
+
+ if (!np) {
+ dev_err(&pdev->dev, "Missing SDMMC description in devicetree\n");
+ return -EFAULT;
+ }
+
+ regular_irq = irq_of_parse_and_map(np, 0);
+ dma_irq = irq_of_parse_and_map(np, 1);
+
+ if (!regular_irq || !dma_irq) {
+ dev_err(&pdev->dev, "Getting IRQs failed!\n");
+ ret = -ENXIO;
+ goto fail1;
+ }
+
+ mmc = mmc_alloc_host(sizeof(struct wmt_mci_priv), &pdev->dev);
+ if (!mmc) {
+ dev_err(&pdev->dev, "Failed to allocate mmc_host\n");
+ ret = -ENOMEM;
+ goto fail1;
+ }
+
+ mmc->ops = &wmt_mci_ops;
+ mmc->f_min = wmt_caps->f_min;
+ mmc->f_max = wmt_caps->f_max;
+ mmc->ocr_avail = wmt_caps->ocr_avail;
+ mmc->caps = wmt_caps->caps;
+
+ mmc->max_seg_size = wmt_caps->max_seg_size;
+ mmc->max_segs = wmt_caps->max_segs;
+ mmc->max_blk_size = wmt_caps->max_blk_size;
+
+ mmc->max_req_size = (16*512*mmc->max_segs);
+ mmc->max_blk_count = mmc->max_req_size / 512;
+
+ priv = mmc_priv(mmc);
+ priv->mmc = mmc;
+ priv->dev = &pdev->dev;
+
+ priv->power_inverted = 0;
+ priv->cd_inverted = 0;
+
+ if (of_get_property(np, "sdon-inverted", NULL))
+ priv->power_inverted = 1;
+ if (of_get_property(np, "cd-inverted", NULL))
+ priv->cd_inverted = 1;
+
+ priv->sdmmc_base = of_iomap(np, 0);
+ if (!priv->sdmmc_base) {
+ dev_err(&pdev->dev, "Failed to map IO space\n");
+ ret = -ENOMEM;
+ goto fail2;
+ }
+
+ priv->irq_regular = regular_irq;
+ priv->irq_dma = dma_irq;
+
+ ret = request_irq(regular_irq, wmt_mci_regular_isr, 0, "sdmmc", priv);
+ if (ret) {
+ dev_err(&pdev->dev, "Register regular IRQ fail\n");
+ goto fail3;
+ }
+
+ ret = request_irq(dma_irq, wmt_mci_dma_isr, 32, "sdmmc", priv);
+ if (ret) {
+ dev_err(&pdev->dev, "Register DMA IRQ fail\n");
+ goto fail4;
+ }
+
+ /* alloc some DMA buffers for descriptors/transfers */
+ priv->dma_desc_buffer = dma_alloc_coherent(&pdev->dev,
+ mmc->max_blk_count * 16,
+ &priv->dma_desc_device_addr,
+ 208);
+ if (!priv->dma_desc_buffer) {
+ dev_err(&pdev->dev, "DMA alloc fail\n");
+ ret = -EPERM;
+ goto fail5;
+ }
+
+ platform_set_drvdata(pdev, mmc);
+
+ priv->clk_sdmmc = of_clk_get(np, 0);
+ if (IS_ERR(priv->clk_sdmmc)) {
+ dev_err(&pdev->dev, "Error getting clock\n");
+ ret = PTR_ERR(priv->clk_sdmmc);
+ goto fail5;
+ }
+
+ clk_prepare_enable(priv->clk_sdmmc);
+
+ /* configure the controller to a known 'ready' state */
+ wmt_reset_hardware(mmc);
+
+ mmc_add_host(mmc);
+
+ dev_info(&pdev->dev, "WMT SDHC Controller initialized\n");
+
+ return 0;
+fail5:
+ free_irq(dma_irq, priv);
+fail4:
+ free_irq(regular_irq, priv);
+fail3:
+ iounmap(priv->sdmmc_base);
+fail2:
+ mmc_free_host(mmc);
+fail1:
+ return ret;
+}
+
+static int __devexit wmt_mci_remove(struct platform_device *pdev)
+{
+ struct mmc_host *mmc;
+ struct wmt_mci_priv *priv;
+ struct resource *res;
+ u32 reg_tmp;
+
+ mmc = platform_get_drvdata(pdev);
+ priv = mmc_priv(mmc);
+
+ /* reset SD controller */
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writel(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + SDMMC_BUSMODE);
+ reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN);
+ writew(reg_tmp & ~(0xA000), priv->sdmmc_base + SDMMC_BLKLEN);
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS0);
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS1);
+
+ /* release the dma buffers */
+ dma_free_coherent(&pdev->dev, priv->mmc->max_blk_count * 16,
+ priv->dma_desc_buffer, priv->dma_desc_device_addr);
+
+ mmc_remove_host(mmc);
+
+ free_irq(priv->irq_regular, priv);
+ free_irq(priv->irq_dma, priv);
+
+ iounmap(priv->sdmmc_base);
+
+ clk_disable_unprepare(priv->clk_sdmmc);
+ clk_put(priv->clk_sdmmc);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ mmc_free_host(mmc);
+
+ platform_set_drvdata(pdev, NULL);
+
+ dev_info(&pdev->dev, "WMT MCI device removed\n");
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int wmt_mci_suspend(struct device *dev)
+{
+ u32 reg_tmp;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct wmt_mci_priv *priv;
+ int ret;
+
+ if (!mmc)
+ return 0;
+
+ priv = mmc_priv(mmc);
+ ret = mmc_suspend_host(mmc);
+
+ if (!ret) {
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base +
+ SDMMC_BUSMODE);
+
+ reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN);
+ writew(reg_tmp & 0x5FFF, priv->sdmmc_base + SDMMC_BLKLEN);
+
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS0);
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS1);
+
+ clk_disable(priv->clk_sdmmc);
+ }
+ return ret;
+}
+
+static int wmt_mci_resume(struct device *dev)
+{
+ u32 reg_tmp;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct wmt_mci_priv *priv;
+ int ret = 0;
+
+ if (mmc) {
+ priv = mmc_priv(mmc);
+ clk_enable(priv->clk_sdmmc);
+
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base +
+ SDMMC_BUSMODE);
+
+ reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN);
+ writew(reg_tmp | (BLKL_GPI_CD | BLKL_INT_ENABLE),
+ priv->sdmmc_base + SDMMC_BLKLEN);
+
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_INTMASK0);
+ writeb(reg_tmp | INT0_DI_INT_EN, priv->sdmmc_base +
+ SDMMC_INTMASK0);
+
+ ret = mmc_resume_host(mmc);
+ }
+
+ return ret;
+}
+
+static const struct dev_pm_ops wmt_mci_pm = {
+ .suspend = wmt_mci_suspend,
+ .resume = wmt_mci_resume,
+};
+
+#define wmt_mci_pm_ops (&wmt_mci_pm)
+
+#else /* !CONFIG_PM */
+
+#define wmt_mci_pm_ops NULL
+
+#endif
+
+static struct platform_driver wmt_mci_driver = {
+ .probe = wmt_mci_probe,
+ .remove = __exit_p(wmt_mci_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .pm = wmt_mci_pm_ops,
+ .of_match_table = wmt_mci_dt_ids,
+ },
+};
+
+module_platform_driver(wmt_mci_driver);
+
+MODULE_DESCRIPTION("Wondermedia MMC/SD Driver");
+MODULE_AUTHOR("Tony Prisk");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, wmt_mci_dt_ids);
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 374c46dff7dd..ec794a72975d 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1077,7 +1077,8 @@ EXPORT_SYMBOL_GPL(mtd_writev);
* until the request succeeds or until the allocation size falls below
* the system page size. This attempts to make sure it does not adversely
* impact system performance, so when allocating more than one page, we
- * ask the memory allocator to avoid re-trying.
+ * ask the memory allocator to avoid re-trying, swapping, writing back
+ * or performing I/O.
*
* Note, this function also makes sure that the allocated buffer is aligned to
* the MTD device's min. I/O unit, i.e. the "mtd->writesize" value.
@@ -1091,7 +1092,8 @@ EXPORT_SYMBOL_GPL(mtd_writev);
*/
void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size)
{
- gfp_t flags = __GFP_NOWARN | __GFP_WAIT | __GFP_NORETRY;
+ gfp_t flags = __GFP_NOWARN | __GFP_WAIT |
+ __GFP_NORETRY | __GFP_NO_KSWAPD;
size_t min_alloc = max_t(size_t, mtd->writesize, PAGE_SIZE);
void *kbuf;
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 914455783302..92623ac2015a 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -41,6 +41,7 @@
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/platform_data/atmel.h>
+#include <linux/pinctrl/consumer.h>
#include <mach/cpu.h>
@@ -1370,6 +1371,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
struct resource *mem;
struct mtd_part_parser_data ppdata = {};
int res;
+ struct pinctrl *pinctrl;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
@@ -1414,6 +1416,13 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
nand_chip->IO_ADDR_W = host->io_base;
nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ dev_err(host->dev, "Failed to request pinctrl\n");
+ res = PTR_ERR(pinctrl);
+ goto err_ecc_ioremap;
+ }
+
if (gpio_is_valid(host->board.rdy_pin)) {
res = gpio_request(host->board.rdy_pin, "nand_rdy");
if (res < 0) {
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index da7b44998b40..2144f611196e 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -498,7 +498,7 @@ out:
* @ubi: UBI device description object
*
* This function returns a physical eraseblock in case of success and a
- * negative error code in case of failure. Might sleep.
+ * negative error code in case of failure.
*/
static int __wl_get_peb(struct ubi_device *ubi)
{
@@ -540,13 +540,6 @@ retry:
* ubi_wl_get_peb() after removing e from the pool. */
prot_queue_add(ubi, e);
#endif
- err = ubi_self_check_all_ff(ubi, e->pnum, ubi->vid_hdr_aloffset,
- ubi->peb_size - ubi->vid_hdr_aloffset);
- if (err) {
- ubi_err("new PEB %d does not contain all 0xFF bytes", e->pnum);
- return err;
- }
-
return e->pnum;
}
@@ -679,17 +672,30 @@ static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi)
#else
static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi)
{
- return find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
+ struct ubi_wl_entry *e;
+
+ e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
+ self_check_in_wl_tree(ubi, e, &ubi->free);
+ rb_erase(&e->u.rb, &ubi->free);
+
+ return e;
}
int ubi_wl_get_peb(struct ubi_device *ubi)
{
- int peb;
+ int peb, err;
spin_lock(&ubi->wl_lock);
peb = __wl_get_peb(ubi);
spin_unlock(&ubi->wl_lock);
+ err = ubi_self_check_all_ff(ubi, peb, ubi->vid_hdr_aloffset,
+ ubi->peb_size - ubi->vid_hdr_aloffset);
+ if (err) {
+ ubi_err("new PEB %d does not contain all 0xFF bytes", peb);
+ return err;
+ }
+
return peb;
}
#endif
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 5f5b69f37d2e..a7d47350ea4b 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3459,6 +3459,28 @@ static int bond_xmit_hash_policy_l34(struct sk_buff *skb, int count)
/*-------------------------- Device entry points ----------------------------*/
+static void bond_work_init_all(struct bonding *bond)
+{
+ INIT_DELAYED_WORK(&bond->mcast_work,
+ bond_resend_igmp_join_requests_delayed);
+ INIT_DELAYED_WORK(&bond->alb_work, bond_alb_monitor);
+ INIT_DELAYED_WORK(&bond->mii_work, bond_mii_monitor);
+ if (bond->params.mode == BOND_MODE_ACTIVEBACKUP)
+ INIT_DELAYED_WORK(&bond->arp_work, bond_activebackup_arp_mon);
+ else
+ INIT_DELAYED_WORK(&bond->arp_work, bond_loadbalance_arp_mon);
+ INIT_DELAYED_WORK(&bond->ad_work, bond_3ad_state_machine_handler);
+}
+
+static void bond_work_cancel_all(struct bonding *bond)
+{
+ cancel_delayed_work_sync(&bond->mii_work);
+ cancel_delayed_work_sync(&bond->arp_work);
+ cancel_delayed_work_sync(&bond->alb_work);
+ cancel_delayed_work_sync(&bond->ad_work);
+ cancel_delayed_work_sync(&bond->mcast_work);
+}
+
static int bond_open(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
@@ -3481,41 +3503,27 @@ static int bond_open(struct net_device *bond_dev)
}
read_unlock(&bond->lock);
- INIT_DELAYED_WORK(&bond->mcast_work, bond_resend_igmp_join_requests_delayed);
+ bond_work_init_all(bond);
if (bond_is_lb(bond)) {
/* bond_alb_initialize must be called before the timer
* is started.
*/
- if (bond_alb_initialize(bond, (bond->params.mode == BOND_MODE_ALB))) {
- /* something went wrong - fail the open operation */
+ if (bond_alb_initialize(bond, (bond->params.mode == BOND_MODE_ALB)))
return -ENOMEM;
- }
-
- INIT_DELAYED_WORK(&bond->alb_work, bond_alb_monitor);
queue_delayed_work(bond->wq, &bond->alb_work, 0);
}
- if (bond->params.miimon) { /* link check interval, in milliseconds. */
- INIT_DELAYED_WORK(&bond->mii_work, bond_mii_monitor);
+ if (bond->params.miimon) /* link check interval, in milliseconds. */
queue_delayed_work(bond->wq, &bond->mii_work, 0);
- }
if (bond->params.arp_interval) { /* arp interval, in milliseconds. */
- if (bond->params.mode == BOND_MODE_ACTIVEBACKUP)
- INIT_DELAYED_WORK(&bond->arp_work,
- bond_activebackup_arp_mon);
- else
- INIT_DELAYED_WORK(&bond->arp_work,
- bond_loadbalance_arp_mon);
-
queue_delayed_work(bond->wq, &bond->arp_work, 0);
if (bond->params.arp_validate)
bond->recv_probe = bond_arp_rcv;
}
if (bond->params.mode == BOND_MODE_8023AD) {
- INIT_DELAYED_WORK(&bond->ad_work, bond_3ad_state_machine_handler);
queue_delayed_work(bond->wq, &bond->ad_work, 0);
/* register to receive LACPDUs */
bond->recv_probe = bond_3ad_lacpdu_recv;
@@ -3530,34 +3538,10 @@ static int bond_close(struct net_device *bond_dev)
struct bonding *bond = netdev_priv(bond_dev);
write_lock_bh(&bond->lock);
-
bond->send_peer_notif = 0;
-
write_unlock_bh(&bond->lock);
- if (bond->params.miimon) { /* link check interval, in milliseconds. */
- cancel_delayed_work_sync(&bond->mii_work);
- }
-
- if (bond->params.arp_interval) { /* arp interval, in milliseconds. */
- cancel_delayed_work_sync(&bond->arp_work);
- }
-
- switch (bond->params.mode) {
- case BOND_MODE_8023AD:
- cancel_delayed_work_sync(&bond->ad_work);
- break;
- case BOND_MODE_TLB:
- case BOND_MODE_ALB:
- cancel_delayed_work_sync(&bond->alb_work);
- break;
- default:
- break;
- }
-
- if (delayed_work_pending(&bond->mcast_work))
- cancel_delayed_work_sync(&bond->mcast_work);
-
+ bond_work_cancel_all(bond);
if (bond_is_lb(bond)) {
/* Must be called only after all
* slaves have been released
@@ -4436,26 +4420,6 @@ static void bond_setup(struct net_device *bond_dev)
bond_dev->features |= bond_dev->hw_features;
}
-static void bond_work_cancel_all(struct bonding *bond)
-{
- if (bond->params.miimon && delayed_work_pending(&bond->mii_work))
- cancel_delayed_work_sync(&bond->mii_work);
-
- if (bond->params.arp_interval && delayed_work_pending(&bond->arp_work))
- cancel_delayed_work_sync(&bond->arp_work);
-
- if (bond->params.mode == BOND_MODE_ALB &&
- delayed_work_pending(&bond->alb_work))
- cancel_delayed_work_sync(&bond->alb_work);
-
- if (bond->params.mode == BOND_MODE_8023AD &&
- delayed_work_pending(&bond->ad_work))
- cancel_delayed_work_sync(&bond->ad_work);
-
- if (delayed_work_pending(&bond->mcast_work))
- cancel_delayed_work_sync(&bond->mcast_work);
-}
-
/*
* Destroy a bonding device.
* Must be under rtnl_lock when this function is called.
@@ -4706,12 +4670,13 @@ static int bond_check_params(struct bond_params *params)
arp_ip_count++) {
/* not complete check, but should be good enough to
catch mistakes */
- if (!isdigit(arp_ip_target[arp_ip_count][0])) {
+ __be32 ip = in_aton(arp_ip_target[arp_ip_count]);
+ if (!isdigit(arp_ip_target[arp_ip_count][0]) ||
+ ip == 0 || ip == htonl(INADDR_BROADCAST)) {
pr_warning("Warning: bad arp_ip_target module parameter (%s), ARP monitoring will not be performed\n",
arp_ip_target[arp_ip_count]);
arp_interval = 0;
} else {
- __be32 ip = in_aton(arp_ip_target[arp_ip_count]);
arp_target[arp_ip_count] = ip;
}
}
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index ef8d2a080d17..1877ed7ca086 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -513,6 +513,8 @@ static ssize_t bonding_store_arp_interval(struct device *d,
int new_value, ret = count;
struct bonding *bond = to_bond(d);
+ if (!rtnl_trylock())
+ return restart_syscall();
if (sscanf(buf, "%d", &new_value) != 1) {
pr_err("%s: no arp_interval value specified.\n",
bond->dev->name);
@@ -539,10 +541,6 @@ static ssize_t bonding_store_arp_interval(struct device *d,
pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n",
bond->dev->name, bond->dev->name);
bond->params.miimon = 0;
- if (delayed_work_pending(&bond->mii_work)) {
- cancel_delayed_work(&bond->mii_work);
- flush_workqueue(bond->wq);
- }
}
if (!bond->params.arp_targets[0]) {
pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified.\n",
@@ -554,19 +552,12 @@ static ssize_t bonding_store_arp_interval(struct device *d,
* timer will get fired off when the open function
* is called.
*/
- if (!delayed_work_pending(&bond->arp_work)) {
- if (bond->params.mode == BOND_MODE_ACTIVEBACKUP)
- INIT_DELAYED_WORK(&bond->arp_work,
- bond_activebackup_arp_mon);
- else
- INIT_DELAYED_WORK(&bond->arp_work,
- bond_loadbalance_arp_mon);
-
- queue_delayed_work(bond->wq, &bond->arp_work, 0);
- }
+ cancel_delayed_work_sync(&bond->mii_work);
+ queue_delayed_work(bond->wq, &bond->arp_work, 0);
}
out:
+ rtnl_unlock();
return ret;
}
static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR,
@@ -962,6 +953,8 @@ static ssize_t bonding_store_miimon(struct device *d,
int new_value, ret = count;
struct bonding *bond = to_bond(d);
+ if (!rtnl_trylock())
+ return restart_syscall();
if (sscanf(buf, "%d", &new_value) != 1) {
pr_err("%s: no miimon value specified.\n",
bond->dev->name);
@@ -993,10 +986,6 @@ static ssize_t bonding_store_miimon(struct device *d,
bond->params.arp_validate =
BOND_ARP_VALIDATE_NONE;
}
- if (delayed_work_pending(&bond->arp_work)) {
- cancel_delayed_work(&bond->arp_work);
- flush_workqueue(bond->wq);
- }
}
if (bond->dev->flags & IFF_UP) {
@@ -1005,15 +994,12 @@ static ssize_t bonding_store_miimon(struct device *d,
* timer will get fired off when the open function
* is called.
*/
- if (!delayed_work_pending(&bond->mii_work)) {
- INIT_DELAYED_WORK(&bond->mii_work,
- bond_mii_monitor);
- queue_delayed_work(bond->wq,
- &bond->mii_work, 0);
- }
+ cancel_delayed_work_sync(&bond->arp_work);
+ queue_delayed_work(bond->wq, &bond->mii_work, 0);
}
}
out:
+ rtnl_unlock();
return ret;
}
static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR,
@@ -1582,6 +1568,7 @@ static ssize_t bonding_store_slaves_active(struct device *d,
goto out;
}
+ read_lock(&bond->lock);
bond_for_each_slave(bond, slave, i) {
if (!bond_is_active_slave(slave)) {
if (new_value)
@@ -1590,6 +1577,7 @@ static ssize_t bonding_store_slaves_active(struct device *d,
slave->inactive = 1;
}
}
+ read_unlock(&bond->lock);
out:
return ret;
}
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
index 86f26a1ede4c..25723d8ee201 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -519,8 +519,10 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n,
mc->pdev->dev.can.state = new_state;
if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) {
+ struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb);
+
peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv);
- skb->tstamp = timeval_to_ktime(tv);
+ hwts->hwtstamp = timeval_to_ktime(tv);
}
netif_rx(skb);
@@ -605,6 +607,7 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
struct sk_buff *skb;
struct can_frame *cf;
struct timeval tv;
+ struct skb_shared_hwtstamps *hwts;
skb = alloc_can_skb(mc->netdev, &cf);
if (!skb)
@@ -652,7 +655,8 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
/* convert timestamp into kernel time */
peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv);
- skb->tstamp = timeval_to_ktime(tv);
+ hwts = skb_hwtstamps(skb);
+ hwts->hwtstamp = timeval_to_ktime(tv);
/* push the skb */
netif_rx(skb);
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
index e1626d92511a..30d79bfa5b10 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
@@ -532,6 +532,7 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if,
struct can_frame *can_frame;
struct sk_buff *skb;
struct timeval tv;
+ struct skb_shared_hwtstamps *hwts;
skb = alloc_can_skb(netdev, &can_frame);
if (!skb)
@@ -549,7 +550,8 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if,
memcpy(can_frame->data, rx->data, can_frame->can_dlc);
peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(rx->ts32), &tv);
- skb->tstamp = timeval_to_ktime(tv);
+ hwts = skb_hwtstamps(skb);
+ hwts->hwtstamp = timeval_to_ktime(tv);
netif_rx(skb);
netdev->stats.rx_packets++;
@@ -570,6 +572,7 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if,
u8 err_mask = 0;
struct sk_buff *skb;
struct timeval tv;
+ struct skb_shared_hwtstamps *hwts;
/* nothing should be sent while in BUS_OFF state */
if (dev->can.state == CAN_STATE_BUS_OFF)
@@ -664,7 +667,8 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if,
dev->can.state = new_state;
peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(er->ts32), &tv);
- skb->tstamp = timeval_to_ktime(tv);
+ hwts = skb_hwtstamps(skb);
+ hwts->hwtstamp = timeval_to_ktime(tv);
netif_rx(skb);
netdev->stats.rx_packets++;
netdev->stats.rx_bytes += can_frame->can_dlc;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
index 5d36795877cb..b799ab12a291 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
@@ -237,7 +237,7 @@ static int mlx4_en_dcbnl_ieee_setmaxrate(struct net_device *dev,
if (err)
return err;
- memcpy(priv->maxrate, tmp, sizeof(*priv->maxrate));
+ memcpy(priv->maxrate, tmp, sizeof(priv->maxrate));
return 0;
}
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
index b01f83a044c4..609125a249d9 100644
--- a/drivers/net/ethernet/realtek/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -1060,17 +1060,22 @@ static int cp_init_rings (struct cp_private *cp)
static int cp_alloc_rings (struct cp_private *cp)
{
+ struct device *d = &cp->pdev->dev;
void *mem;
+ int rc;
- mem = dma_alloc_coherent(&cp->pdev->dev, CP_RING_BYTES,
- &cp->ring_dma, GFP_KERNEL);
+ mem = dma_alloc_coherent(d, CP_RING_BYTES, &cp->ring_dma, GFP_KERNEL);
if (!mem)
return -ENOMEM;
cp->rx_ring = mem;
cp->tx_ring = &cp->rx_ring[CP_RX_RING_SIZE];
- return cp_init_rings(cp);
+ rc = cp_init_rings(cp);
+ if (rc < 0)
+ dma_free_coherent(d, CP_RING_BYTES, cp->rx_ring, cp->ring_dma);
+
+ return rc;
}
static void cp_clean_rings (struct cp_private *cp)
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index d44cca327588..ad86660fb8f9 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1794,10 +1794,12 @@ static void team_setup(struct net_device *dev)
dev->features |= NETIF_F_LLTX;
dev->features |= NETIF_F_GRO;
- dev->hw_features = NETIF_F_HW_VLAN_TX |
+ dev->hw_features = TEAM_VLAN_FEATURES |
+ NETIF_F_HW_VLAN_TX |
NETIF_F_HW_VLAN_RX |
NETIF_F_HW_VLAN_FILTER;
+ dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_HW_CSUM);
dev->features |= dev->hw_features;
}
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 3b566fa0f8e6..1ea91f4237f0 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -385,6 +385,7 @@ static const struct usb_device_id products[] = {
},
/* 3. Combined interface devices matching on interface number */
+ {QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */
{QMI_FIXED_INTF(0x19d2, 0x0002, 1)},
{QMI_FIXED_INTF(0x19d2, 0x0012, 1)},
{QMI_FIXED_INTF(0x19d2, 0x0017, 3)},
diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c
index e9a3da588e95..760776b3d66c 100644
--- a/drivers/net/wan/ixp4xx_hss.c
+++ b/drivers/net/wan/ixp4xx_hss.c
@@ -1365,7 +1365,7 @@ static int __devinit hss_init_one(struct platform_device *pdev)
platform_set_drvdata(pdev, port);
- netdev_info(dev, "HSS-%i\n", port->id);
+ netdev_info(dev, "initialized\n");
return 0;
err_free_netdev:
diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c
index 10896393e5a0..2830ea290502 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rxon.c
+++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c
@@ -1012,12 +1012,12 @@ static void iwl_calc_basic_rates(struct iwl_priv *priv,
* As a consequence, it's not as complicated as it sounds, just add
* any lower rates to the ACK rate bitmap.
*/
- if (IWL_RATE_11M_INDEX < lowest_present_ofdm)
- ofdm |= IWL_RATE_11M_MASK >> IWL_FIRST_CCK_RATE;
- if (IWL_RATE_5M_INDEX < lowest_present_ofdm)
- ofdm |= IWL_RATE_5M_MASK >> IWL_FIRST_CCK_RATE;
- if (IWL_RATE_2M_INDEX < lowest_present_ofdm)
- ofdm |= IWL_RATE_2M_MASK >> IWL_FIRST_CCK_RATE;
+ if (IWL_RATE_11M_INDEX < lowest_present_cck)
+ cck |= IWL_RATE_11M_MASK >> IWL_FIRST_CCK_RATE;
+ if (IWL_RATE_5M_INDEX < lowest_present_cck)
+ cck |= IWL_RATE_5M_MASK >> IWL_FIRST_CCK_RATE;
+ if (IWL_RATE_2M_INDEX < lowest_present_cck)
+ cck |= IWL_RATE_2M_MASK >> IWL_FIRST_CCK_RATE;
/* 1M already there or needed so always add */
cck |= IWL_RATE_1M_MASK >> IWL_FIRST_CCK_RATE;
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index aeecf0f72cad..390ab69ea569 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -26,6 +26,15 @@ config DEBUG_PINCTRL
help
Say Y here to add some extra checks and diagnostics to PINCTRL calls.
+config PINCTRL_AT91
+ bool "AT91 pinctrl driver"
+ depends on OF
+ depends on ARCH_AT91
+ select PINMUX
+ select PINCONF
+ help
+ Say Y here to enable the at91 pinctrl driver
+
config PINCTRL_BCM2835
bool
select PINMUX
@@ -87,21 +96,18 @@ config PINCTRL_MMP2
bool "MMP2 pin controller driver"
depends on ARCH_MMP
select PINCTRL_PXA3xx
- select PINCONF
config PINCTRL_MXS
bool
+ select PINMUX
+ select PINCONF
config PINCTRL_IMX23
bool
- select PINMUX
- select PINCONF
select PINCTRL_MXS
config PINCTRL_IMX28
bool
- select PINMUX
- select PINCONF
select PINCTRL_MXS
config PINCTRL_NOMADIK
@@ -126,13 +132,11 @@ config PINCTRL_PXA168
bool "PXA168 pin controller driver"
depends on ARCH_MMP
select PINCTRL_PXA3xx
- select PINCONF
config PINCTRL_PXA910
bool "PXA910 pin controller driver"
depends on ARCH_MMP
select PINCTRL_PXA3xx
- select PINCONF
config PINCTRL_SINGLE
tristate "One-register-per-pin type device tree based pinctrl driver"
@@ -143,23 +147,21 @@ config PINCTRL_SINGLE
This selects the device tree based generic pinctrl driver.
config PINCTRL_SIRF
- bool "CSR SiRFprimaII pin controller driver"
- depends on ARCH_PRIMA2
+ bool "CSR SiRFprimaII/SiRFmarco pin controller driver"
+ depends on ARCH_SIRF
select PINMUX
config PINCTRL_TEGRA
bool
+ select PINMUX
+ select PINCONF
config PINCTRL_TEGRA20
bool
- select PINMUX
- select PINCONF
select PINCTRL_TEGRA
config PINCTRL_TEGRA30
bool
- select PINMUX
- select PINCONF
select PINCTRL_TEGRA
config PINCTRL_U300
@@ -188,27 +190,7 @@ config PINCTRL_EXYNOS4
depends on OF && GPIOLIB
select PINCTRL_SAMSUNG
-config PINCTRL_MVEBU
- bool
- depends on ARCH_MVEBU
- select PINMUX
- select PINCONF
-
-config PINCTRL_DOVE
- bool
- select PINCTRL_MVEBU
-
-config PINCTRL_KIRKWOOD
- bool
- select PINCTRL_MVEBU
-
-config PINCTRL_ARMADA_370
- bool
- select PINCTRL_MVEBU
-
-config PINCTRL_ARMADA_XP
- bool
- select PINCTRL_MVEBU
+source "drivers/pinctrl/mvebu/Kconfig"
source "drivers/pinctrl/spear/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index f395ba5cec25..f95f5ed923be 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -9,6 +9,7 @@ ifeq ($(CONFIG_OF),y)
obj-$(CONFIG_PINCTRL) += devicetree.o
endif
obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
+obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o
obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o
obj-$(CONFIG_PINCTRL_IMX35) += pinctrl-imx35.o
@@ -36,12 +37,8 @@ obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o
obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o
obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o
obj-$(CONFIG_PINCTRL_EXYNOS4) += pinctrl-exynos.o
-obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o
-obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o
-obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o
-obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o
-obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o
obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o
obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o
+obj-$(CONFIG_PLAT_ORION) += mvebu/
obj-$(CONFIG_PLAT_SPEAR) += spear/
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 2e39c04fc16b..5cdee8669ea3 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -345,6 +345,62 @@ void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
}
EXPORT_SYMBOL_GPL(pinctrl_add_gpio_ranges);
+struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname,
+ struct pinctrl_gpio_range *range)
+{
+ struct pinctrl_dev *pctldev = get_pinctrl_dev_from_devname(devname);
+
+ /*
+ * If we can't find this device, let's assume that is because
+ * it has not probed yet, so the driver trying to register this
+ * range need to defer probing.
+ */
+ if (!pctldev)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ pinctrl_add_gpio_range(pctldev, range);
+ return pctldev;
+}
+EXPORT_SYMBOL_GPL(pinctrl_find_and_add_gpio_range);
+
+/**
+ * pinctrl_find_gpio_range_from_pin() - locate the GPIO range for a pin
+ * @pctldev: the pin controller device to look in
+ * @pin: a controller-local number to find the range for
+ */
+struct pinctrl_gpio_range *
+pinctrl_find_gpio_range_from_pin(struct pinctrl_dev *pctldev,
+ unsigned int pin)
+{
+ struct pinctrl_gpio_range *range = NULL;
+
+ /* Loop over the ranges */
+ list_for_each_entry(range, &pctldev->gpio_ranges, node) {
+ /* Check if we're in the valid range */
+ if (pin >= range->pin_base &&
+ pin < range->pin_base + range->npins) {
+ return range;
+ }
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(pinctrl_find_gpio_range_from_pin);
+
+/**
+ * pinctrl_remove_gpio_range() - remove a range of GPIOs fro a pin controller
+ * @pctldev: pin controller device to remove the range from
+ * @range: the GPIO range to remove
+ */
+void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range)
+{
+ mutex_lock(&pinctrl_mutex);
+ list_del(&range->node);
+ mutex_unlock(&pinctrl_mutex);
+}
+EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range);
+
/**
* pinctrl_get_group_selector() - returns the group selector for a group
* @pctldev: the pin controller handling the group
@@ -563,6 +619,8 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
return -EPROBE_DEFER;
}
+ setting->dev_name = map->dev_name;
+
switch (map->type) {
case PIN_MAP_TYPE_MUX_GROUP:
ret = pinmux_map_to_setting(map, setting);
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
index 1f40ff68a8c4..12f5694f3d5d 100644
--- a/drivers/pinctrl/core.h
+++ b/drivers/pinctrl/core.h
@@ -105,12 +105,14 @@ struct pinctrl_setting_configs {
* @type: the type of setting
* @pctldev: pin control device handling to be programmed. Not used for
* PIN_MAP_TYPE_DUMMY_STATE.
+ * @dev_name: the name of the device using this state
* @data: Data specific to the setting type
*/
struct pinctrl_setting {
struct list_head node;
enum pinctrl_map_type type;
struct pinctrl_dev *pctldev;
+ const char *dev_name;
union {
struct pinctrl_setting_mux mux;
struct pinctrl_setting_configs configs;
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
index fcb1de45473c..fe2d1af7cfa0 100644
--- a/drivers/pinctrl/devicetree.c
+++ b/drivers/pinctrl/devicetree.c
@@ -106,6 +106,17 @@ static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np)
return NULL;
}
+struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
+{
+ struct pinctrl_dev *pctldev;
+
+ pctldev = find_pinctrl_by_of_node(np);
+ if (!pctldev)
+ return NULL;
+
+ return pctldev;
+}
+
static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
struct device_node *np_config)
{
diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig
new file mode 100644
index 000000000000..366fa541ee91
--- /dev/null
+++ b/drivers/pinctrl/mvebu/Kconfig
@@ -0,0 +1,24 @@
+if PLAT_ORION
+
+config PINCTRL_MVEBU
+ bool
+ select PINMUX
+ select PINCONF
+
+config PINCTRL_DOVE
+ bool
+ select PINCTRL_MVEBU
+
+config PINCTRL_KIRKWOOD
+ bool
+ select PINCTRL_MVEBU
+
+config PINCTRL_ARMADA_370
+ bool
+ select PINCTRL_MVEBU
+
+config PINCTRL_ARMADA_XP
+ bool
+ select PINCTRL_MVEBU
+
+endif
diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile
new file mode 100644
index 000000000000..37c253297af0
--- /dev/null
+++ b/drivers/pinctrl/mvebu/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o
+obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o
+obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o
+obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o
+obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o
diff --git a/drivers/pinctrl/pinctrl-armada-370.c b/drivers/pinctrl/mvebu/pinctrl-armada-370.c
index c907647de6ad..c907647de6ad 100644
--- a/drivers/pinctrl/pinctrl-armada-370.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-370.c
diff --git a/drivers/pinctrl/pinctrl-armada-xp.c b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c
index 40bd52a46b4e..40bd52a46b4e 100644
--- a/drivers/pinctrl/pinctrl-armada-xp.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c
diff --git a/drivers/pinctrl/pinctrl-dove.c b/drivers/pinctrl/mvebu/pinctrl-dove.c
index ffe74b27d66d..ffe74b27d66d 100644
--- a/drivers/pinctrl/pinctrl-dove.c
+++ b/drivers/pinctrl/mvebu/pinctrl-dove.c
diff --git a/drivers/pinctrl/pinctrl-kirkwood.c b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c
index 9a74ef674a0e..9a74ef674a0e 100644
--- a/drivers/pinctrl/pinctrl-kirkwood.c
+++ b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c
diff --git a/drivers/pinctrl/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
index 8e6266c6249a..6c44b7e8964c 100644
--- a/drivers/pinctrl/pinctrl-mvebu.c
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
@@ -24,7 +24,6 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
-#include "core.h"
#include "pinctrl-mvebu.h"
#define MPPS_PER_REG 8
diff --git a/drivers/pinctrl/pinctrl-mvebu.h b/drivers/pinctrl/mvebu/pinctrl-mvebu.h
index 90bd3beee860..90bd3beee860 100644
--- a/drivers/pinctrl/pinctrl-mvebu.h
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.h
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index 33fbaeaa65dd..833a36458157 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -41,6 +41,7 @@ struct pin_config_item conf_items[] = {
PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL),
PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL),
PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL),
+ PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_DISABLE, "input schmitt disabled", NULL),
PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL),
PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "time units"),
PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector"),
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
new file mode 100644
index 000000000000..c5e757157183
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -0,0 +1,1634 @@
+/*
+ * at91 pinctrl driver based on at91 pinmux core
+ *
+ * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2 only
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+/* Since we request GPIOs from ourself */
+#include <linux/pinctrl/consumer.h>
+
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/at91_pio.h>
+
+#include "core.h"
+
+#define MAX_NB_GPIO_PER_BANK 32
+
+struct at91_pinctrl_mux_ops;
+
+struct at91_gpio_chip {
+ struct gpio_chip chip;
+ struct pinctrl_gpio_range range;
+ struct at91_gpio_chip *next; /* Bank sharing same clock */
+ int pioc_hwirq; /* PIO bank interrupt identifier on AIC */
+ int pioc_virq; /* PIO bank Linux virtual interrupt */
+ int pioc_idx; /* PIO bank index */
+ void __iomem *regbase; /* PIO bank virtual address */
+ struct clk *clock; /* associated clock */
+ struct irq_domain *domain; /* associated irq domain */
+ struct at91_pinctrl_mux_ops *ops; /* ops */
+};
+
+#define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
+
+static struct at91_gpio_chip *gpio_chips[MAX_GPIO_BANKS];
+
+static int gpio_banks;
+
+#define PULL_UP (1 << 0)
+#define MULTI_DRIVE (1 << 1)
+#define DEGLITCH (1 << 2)
+#define PULL_DOWN (1 << 3)
+#define DIS_SCHMIT (1 << 4)
+#define DEBOUNCE (1 << 16)
+#define DEBOUNCE_VAL_SHIFT 17
+#define DEBOUNCE_VAL (0x3fff << DEBOUNCE_VAL_SHIFT)
+
+/**
+ * struct at91_pmx_func - describes AT91 pinmux functions
+ * @name: the name of this specific function
+ * @groups: corresponding pin groups
+ * @ngroups: the number of groups
+ */
+struct at91_pmx_func {
+ const char *name;
+ const char **groups;
+ unsigned ngroups;
+};
+
+enum at91_mux {
+ AT91_MUX_GPIO = 0,
+ AT91_MUX_PERIPH_A = 1,
+ AT91_MUX_PERIPH_B = 2,
+ AT91_MUX_PERIPH_C = 3,
+ AT91_MUX_PERIPH_D = 4,
+};
+
+/**
+ * struct at91_pmx_pin - describes an At91 pin mux
+ * @bank: the bank of the pin
+ * @pin: the pin number in the @bank
+ * @mux: the mux mode : gpio or periph_x of the pin i.e. alternate function.
+ * @conf: the configuration of the pin: PULL_UP, MULTIDRIVE etc...
+ */
+struct at91_pmx_pin {
+ uint32_t bank;
+ uint32_t pin;
+ enum at91_mux mux;
+ unsigned long conf;
+};
+
+/**
+ * struct at91_pin_group - describes an At91 pin group
+ * @name: the name of this specific pin group
+ * @pins_conf: the mux mode for each pin in this group. The size of this
+ * array is the same as pins.
+ * @pins: an array of discrete physical pins used in this group, taken
+ * from the driver-local pin enumeration space
+ * @npins: the number of pins in this group array, i.e. the number of
+ * elements in .pins so we can iterate over that array
+ */
+struct at91_pin_group {
+ const char *name;
+ struct at91_pmx_pin *pins_conf;
+ unsigned int *pins;
+ unsigned npins;
+};
+
+/**
+ * struct at91_pinctrl_mux_ops - describes an At91 mux ops group
+ * on new IP with support for periph C and D the way to mux in
+ * periph A and B has changed
+ * So provide the right call back
+ * if not present means the IP does not support it
+ * @get_periph: return the periph mode configured
+ * @mux_A_periph: mux as periph A
+ * @mux_B_periph: mux as periph B
+ * @mux_C_periph: mux as periph C
+ * @mux_D_periph: mux as periph D
+ * @get_deglitch: get deglitch status
+ * @set_deglitch: enable/disable deglitch
+ * @get_debounce: get debounce status
+ * @set_debounce: enable/disable debounce
+ * @get_pulldown: get pulldown status
+ * @set_pulldown: enable/disable pulldown
+ * @get_schmitt_trig: get schmitt trigger status
+ * @disable_schmitt_trig: disable schmitt trigger
+ * @irq_type: return irq type
+ */
+struct at91_pinctrl_mux_ops {
+ enum at91_mux (*get_periph)(void __iomem *pio, unsigned mask);
+ void (*mux_A_periph)(void __iomem *pio, unsigned mask);
+ void (*mux_B_periph)(void __iomem *pio, unsigned mask);
+ void (*mux_C_periph)(void __iomem *pio, unsigned mask);
+ void (*mux_D_periph)(void __iomem *pio, unsigned mask);
+ bool (*get_deglitch)(void __iomem *pio, unsigned pin);
+ void (*set_deglitch)(void __iomem *pio, unsigned mask, bool in_on);
+ bool (*get_debounce)(void __iomem *pio, unsigned pin, u32 *div);
+ void (*set_debounce)(void __iomem *pio, unsigned mask, bool in_on, u32 div);
+ bool (*get_pulldown)(void __iomem *pio, unsigned pin);
+ void (*set_pulldown)(void __iomem *pio, unsigned mask, bool in_on);
+ bool (*get_schmitt_trig)(void __iomem *pio, unsigned pin);
+ void (*disable_schmitt_trig)(void __iomem *pio, unsigned mask);
+ /* irq */
+ int (*irq_type)(struct irq_data *d, unsigned type);
+};
+
+static int gpio_irq_type(struct irq_data *d, unsigned type);
+static int alt_gpio_irq_type(struct irq_data *d, unsigned type);
+
+struct at91_pinctrl {
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+
+ int nbanks;
+
+ uint32_t *mux_mask;
+ int nmux;
+
+ struct at91_pmx_func *functions;
+ int nfunctions;
+
+ struct at91_pin_group *groups;
+ int ngroups;
+
+ struct at91_pinctrl_mux_ops *ops;
+};
+
+static const inline struct at91_pin_group *at91_pinctrl_find_group_by_name(
+ const struct at91_pinctrl *info,
+ const char *name)
+{
+ const struct at91_pin_group *grp = NULL;
+ int i;
+
+ for (i = 0; i < info->ngroups; i++) {
+ if (strcmp(info->groups[i].name, name))
+ continue;
+
+ grp = &info->groups[i];
+ dev_dbg(info->dev, "%s: %d 0:%d\n", name, grp->npins, grp->pins[0]);
+ break;
+ }
+
+ return grp;
+}
+
+static int at91_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ return info->ngroups;
+}
+
+static const char *at91_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ return info->groups[selector].name;
+}
+
+static int at91_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+ const unsigned **pins,
+ unsigned *npins)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ if (selector >= info->ngroups)
+ return -EINVAL;
+
+ *pins = info->groups[selector].pins;
+ *npins = info->groups[selector].npins;
+
+ return 0;
+}
+
+static void at91_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+ unsigned offset)
+{
+ seq_printf(s, "%s", dev_name(pctldev->dev));
+}
+
+static int at91_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np,
+ struct pinctrl_map **map, unsigned *num_maps)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ const struct at91_pin_group *grp;
+ struct pinctrl_map *new_map;
+ struct device_node *parent;
+ int map_num = 1;
+ int i;
+
+ /*
+ * first find the group of this node and check if we need create
+ * config maps for pins
+ */
+ grp = at91_pinctrl_find_group_by_name(info, np->name);
+ if (!grp) {
+ dev_err(info->dev, "unable to find group for node %s\n",
+ np->name);
+ return -EINVAL;
+ }
+
+ map_num += grp->npins;
+ new_map = devm_kzalloc(pctldev->dev, sizeof(*new_map) * map_num, GFP_KERNEL);
+ if (!new_map)
+ return -ENOMEM;
+
+ *map = new_map;
+ *num_maps = map_num;
+
+ /* create mux map */
+ parent = of_get_parent(np);
+ if (!parent) {
+ kfree(new_map);
+ return -EINVAL;
+ }
+ new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
+ new_map[0].data.mux.function = parent->name;
+ new_map[0].data.mux.group = np->name;
+ of_node_put(parent);
+
+ /* create config map */
+ new_map++;
+ for (i = 0; i < grp->npins; i++) {
+ new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
+ new_map[i].data.configs.group_or_pin =
+ pin_get_name(pctldev, grp->pins[i]);
+ new_map[i].data.configs.configs = &grp->pins_conf[i].conf;
+ new_map[i].data.configs.num_configs = 1;
+ }
+
+ dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n",
+ (*map)->data.mux.function, (*map)->data.mux.group, map_num);
+
+ return 0;
+}
+
+static void at91_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned num_maps)
+{
+}
+
+static struct pinctrl_ops at91_pctrl_ops = {
+ .get_groups_count = at91_get_groups_count,
+ .get_group_name = at91_get_group_name,
+ .get_group_pins = at91_get_group_pins,
+ .pin_dbg_show = at91_pin_dbg_show,
+ .dt_node_to_map = at91_dt_node_to_map,
+ .dt_free_map = at91_dt_free_map,
+};
+
+static void __iomem * pin_to_controller(struct at91_pinctrl *info,
+ unsigned int bank)
+{
+ return gpio_chips[bank]->regbase;
+}
+
+static inline int pin_to_bank(unsigned pin)
+{
+ return pin /= MAX_NB_GPIO_PER_BANK;
+}
+
+static unsigned pin_to_mask(unsigned int pin)
+{
+ return 1 << pin;
+}
+
+static void at91_mux_disable_interrupt(void __iomem *pio, unsigned mask)
+{
+ writel_relaxed(mask, pio + PIO_IDR);
+}
+
+static unsigned at91_mux_get_pullup(void __iomem *pio, unsigned pin)
+{
+ return (readl_relaxed(pio + PIO_PUSR) >> pin) & 0x1;
+}
+
+static void at91_mux_set_pullup(void __iomem *pio, unsigned mask, bool on)
+{
+ writel_relaxed(mask, pio + (on ? PIO_PUER : PIO_PUDR));
+}
+
+static unsigned at91_mux_get_multidrive(void __iomem *pio, unsigned pin)
+{
+ return (readl_relaxed(pio + PIO_MDSR) >> pin) & 0x1;
+}
+
+static void at91_mux_set_multidrive(void __iomem *pio, unsigned mask, bool on)
+{
+ writel_relaxed(mask, pio + (on ? PIO_MDER : PIO_MDDR));
+}
+
+static void at91_mux_set_A_periph(void __iomem *pio, unsigned mask)
+{
+ writel_relaxed(mask, pio + PIO_ASR);
+}
+
+static void at91_mux_set_B_periph(void __iomem *pio, unsigned mask)
+{
+ writel_relaxed(mask, pio + PIO_BSR);
+}
+
+static void at91_mux_pio3_set_A_periph(void __iomem *pio, unsigned mask)
+{
+
+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask,
+ pio + PIO_ABCDSR1);
+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask,
+ pio + PIO_ABCDSR2);
+}
+
+static void at91_mux_pio3_set_B_periph(void __iomem *pio, unsigned mask)
+{
+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask,
+ pio + PIO_ABCDSR1);
+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask,
+ pio + PIO_ABCDSR2);
+}
+
+static void at91_mux_pio3_set_C_periph(void __iomem *pio, unsigned mask)
+{
+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1);
+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
+}
+
+static void at91_mux_pio3_set_D_periph(void __iomem *pio, unsigned mask)
+{
+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1);
+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
+}
+
+static enum at91_mux at91_mux_pio3_get_periph(void __iomem *pio, unsigned mask)
+{
+ unsigned select;
+
+ if (readl_relaxed(pio + PIO_PSR) & mask)
+ return AT91_MUX_GPIO;
+
+ select = !!(readl_relaxed(pio + PIO_ABCDSR1) & mask);
+ select |= (!!(readl_relaxed(pio + PIO_ABCDSR2) & mask) << 1);
+
+ return select + 1;
+}
+
+static enum at91_mux at91_mux_get_periph(void __iomem *pio, unsigned mask)
+{
+ unsigned select;
+
+ if (readl_relaxed(pio + PIO_PSR) & mask)
+ return AT91_MUX_GPIO;
+
+ select = readl_relaxed(pio + PIO_ABSR) & mask;
+
+ return select + 1;
+}
+
+static bool at91_mux_get_deglitch(void __iomem *pio, unsigned pin)
+{
+ return (__raw_readl(pio + PIO_IFSR) >> pin) & 0x1;
+}
+
+static void at91_mux_set_deglitch(void __iomem *pio, unsigned mask, bool is_on)
+{
+ __raw_writel(mask, pio + (is_on ? PIO_IFER : PIO_IFDR));
+}
+
+static void at91_mux_pio3_set_deglitch(void __iomem *pio, unsigned mask, bool is_on)
+{
+ if (is_on)
+ __raw_writel(mask, pio + PIO_IFSCDR);
+ at91_mux_set_deglitch(pio, mask, is_on);
+}
+
+static bool at91_mux_pio3_get_debounce(void __iomem *pio, unsigned pin, u32 *div)
+{
+ *div = __raw_readl(pio + PIO_SCDR);
+
+ return (__raw_readl(pio + PIO_IFSCSR) >> pin) & 0x1;
+}
+
+static void at91_mux_pio3_set_debounce(void __iomem *pio, unsigned mask,
+ bool is_on, u32 div)
+{
+ if (is_on) {
+ __raw_writel(mask, pio + PIO_IFSCER);
+ __raw_writel(div & PIO_SCDR_DIV, pio + PIO_SCDR);
+ __raw_writel(mask, pio + PIO_IFER);
+ } else {
+ __raw_writel(mask, pio + PIO_IFDR);
+ }
+}
+
+static bool at91_mux_pio3_get_pulldown(void __iomem *pio, unsigned pin)
+{
+ return (__raw_readl(pio + PIO_PPDSR) >> pin) & 0x1;
+}
+
+static void at91_mux_pio3_set_pulldown(void __iomem *pio, unsigned mask, bool is_on)
+{
+ __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR));
+}
+
+static void at91_mux_pio3_disable_schmitt_trig(void __iomem *pio, unsigned mask)
+{
+ __raw_writel(__raw_readl(pio + PIO_SCHMITT) | mask, pio + PIO_SCHMITT);
+}
+
+static bool at91_mux_pio3_get_schmitt_trig(void __iomem *pio, unsigned pin)
+{
+ return (__raw_readl(pio + PIO_SCHMITT) >> pin) & 0x1;
+}
+
+static struct at91_pinctrl_mux_ops at91rm9200_ops = {
+ .get_periph = at91_mux_get_periph,
+ .mux_A_periph = at91_mux_set_A_periph,
+ .mux_B_periph = at91_mux_set_B_periph,
+ .get_deglitch = at91_mux_get_deglitch,
+ .set_deglitch = at91_mux_set_deglitch,
+ .irq_type = gpio_irq_type,
+};
+
+static struct at91_pinctrl_mux_ops at91sam9x5_ops = {
+ .get_periph = at91_mux_pio3_get_periph,
+ .mux_A_periph = at91_mux_pio3_set_A_periph,
+ .mux_B_periph = at91_mux_pio3_set_B_periph,
+ .mux_C_periph = at91_mux_pio3_set_C_periph,
+ .mux_D_periph = at91_mux_pio3_set_D_periph,
+ .get_deglitch = at91_mux_get_deglitch,
+ .set_deglitch = at91_mux_pio3_set_deglitch,
+ .get_debounce = at91_mux_pio3_get_debounce,
+ .set_debounce = at91_mux_pio3_set_debounce,
+ .get_pulldown = at91_mux_pio3_get_pulldown,
+ .set_pulldown = at91_mux_pio3_set_pulldown,
+ .get_schmitt_trig = at91_mux_pio3_get_schmitt_trig,
+ .disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig,
+ .irq_type = alt_gpio_irq_type,
+};
+
+static void at91_pin_dbg(const struct device *dev, const struct at91_pmx_pin *pin)
+{
+ if (pin->mux) {
+ dev_dbg(dev, "pio%c%d configured as periph%c with conf = 0x%lu\n",
+ pin->bank + 'A', pin->pin, pin->mux - 1 + 'A', pin->conf);
+ } else {
+ dev_dbg(dev, "pio%c%d configured as gpio with conf = 0x%lu\n",
+ pin->bank + 'A', pin->pin, pin->conf);
+ }
+}
+
+static int pin_check_config(struct at91_pinctrl *info, const char* name,
+ int index, const struct at91_pmx_pin *pin)
+{
+ int mux;
+
+ /* check if it's a valid config */
+ if (pin->bank >= info->nbanks) {
+ dev_err(info->dev, "%s: pin conf %d bank_id %d >= nbanks %d\n",
+ name, index, pin->bank, info->nbanks);
+ return -EINVAL;
+ }
+
+ if (pin->pin >= MAX_NB_GPIO_PER_BANK) {
+ dev_err(info->dev, "%s: pin conf %d pin_bank_id %d >= %d\n",
+ name, index, pin->pin, MAX_NB_GPIO_PER_BANK);
+ return -EINVAL;
+ }
+
+ if (!pin->mux)
+ return 0;
+
+ mux = pin->mux - 1;
+
+ if (mux >= info->nmux) {
+ dev_err(info->dev, "%s: pin conf %d mux_id %d >= nmux %d\n",
+ name, index, mux, info->nmux);
+ return -EINVAL;
+ }
+
+ if (!(info->mux_mask[pin->bank * info->nmux + mux] & 1 << pin->pin)) {
+ dev_err(info->dev, "%s: pin conf %d mux_id %d not supported for pio%c%d\n",
+ name, index, mux, pin->bank + 'A', pin->pin);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void at91_mux_gpio_disable(void __iomem *pio, unsigned mask)
+{
+ writel_relaxed(mask, pio + PIO_PDR);
+}
+
+static void at91_mux_gpio_enable(void __iomem *pio, unsigned mask, bool input)
+{
+ writel_relaxed(mask, pio + PIO_PER);
+ writel_relaxed(mask, pio + (input ? PIO_ODR : PIO_OER));
+}
+
+static int at91_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
+ unsigned group)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf;
+ const struct at91_pmx_pin *pin;
+ uint32_t npins = info->groups[group].npins;
+ int i, ret;
+ unsigned mask;
+ void __iomem *pio;
+
+ dev_dbg(info->dev, "enable function %s group %s\n",
+ info->functions[selector].name, info->groups[group].name);
+
+ /* first check that all the pins of the group are valid with a valid
+ * paramter */
+ for (i = 0; i < npins; i++) {
+ pin = &pins_conf[i];
+ ret = pin_check_config(info, info->groups[group].name, i, pin);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < npins; i++) {
+ pin = &pins_conf[i];
+ at91_pin_dbg(info->dev, pin);
+ pio = pin_to_controller(info, pin->bank);
+ mask = pin_to_mask(pin->pin);
+ at91_mux_disable_interrupt(pio, mask);
+ switch(pin->mux) {
+ case AT91_MUX_GPIO:
+ at91_mux_gpio_enable(pio, mask, 1);
+ break;
+ case AT91_MUX_PERIPH_A:
+ info->ops->mux_A_periph(pio, mask);
+ break;
+ case AT91_MUX_PERIPH_B:
+ info->ops->mux_B_periph(pio, mask);
+ break;
+ case AT91_MUX_PERIPH_C:
+ if (!info->ops->mux_C_periph)
+ return -EINVAL;
+ info->ops->mux_C_periph(pio, mask);
+ break;
+ case AT91_MUX_PERIPH_D:
+ if (!info->ops->mux_D_periph)
+ return -EINVAL;
+ info->ops->mux_D_periph(pio, mask);
+ break;
+ }
+ if (pin->mux)
+ at91_mux_gpio_disable(pio, mask);
+ }
+
+ return 0;
+}
+
+static void at91_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
+ unsigned group)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf;
+ const struct at91_pmx_pin *pin;
+ uint32_t npins = info->groups[group].npins;
+ int i;
+ unsigned mask;
+ void __iomem *pio;
+
+ for (i = 0; i < npins; i++) {
+ pin = &pins_conf[i];
+ at91_pin_dbg(info->dev, pin);
+ pio = pin_to_controller(info, pin->bank);
+ mask = pin_to_mask(pin->pin);
+ at91_mux_gpio_enable(pio, mask, 1);
+ }
+}
+
+static int at91_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ return info->nfunctions;
+}
+
+static const char *at91_pmx_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ return info->functions[selector].name;
+}
+
+static int at91_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = info->functions[selector].groups;
+ *num_groups = info->functions[selector].ngroups;
+
+ return 0;
+}
+
+static int at91_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+ struct at91_gpio_chip *at91_chip;
+ struct gpio_chip *chip;
+ unsigned mask;
+
+ if (!range) {
+ dev_err(npct->dev, "invalid range\n");
+ return -EINVAL;
+ }
+ if (!range->gc) {
+ dev_err(npct->dev, "missing GPIO chip in range\n");
+ return -EINVAL;
+ }
+ chip = range->gc;
+ at91_chip = container_of(chip, struct at91_gpio_chip, chip);
+
+ dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset);
+
+ mask = 1 << (offset - chip->base);
+
+ dev_dbg(npct->dev, "enable pin %u as PIO%c%d 0x%x\n",
+ offset, 'A' + range->id, offset - chip->base, mask);
+
+ writel_relaxed(mask, at91_chip->regbase + PIO_PER);
+
+ return 0;
+}
+
+static void at91_gpio_disable_free(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ dev_dbg(npct->dev, "disable pin %u as GPIO\n", offset);
+ /* Set the pin to some default state, GPIO is usually default */
+}
+
+static struct pinmux_ops at91_pmx_ops = {
+ .get_functions_count = at91_pmx_get_funcs_count,
+ .get_function_name = at91_pmx_get_func_name,
+ .get_function_groups = at91_pmx_get_groups,
+ .enable = at91_pmx_enable,
+ .disable = at91_pmx_disable,
+ .gpio_request_enable = at91_gpio_request_enable,
+ .gpio_disable_free = at91_gpio_disable_free,
+};
+
+static int at91_pinconf_get(struct pinctrl_dev *pctldev,
+ unsigned pin_id, unsigned long *config)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ void __iomem *pio;
+ unsigned pin;
+ int div;
+
+ dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, *config);
+ pio = pin_to_controller(info, pin_to_bank(pin_id));
+ pin = pin_id % MAX_NB_GPIO_PER_BANK;
+
+ if (at91_mux_get_multidrive(pio, pin))
+ *config |= MULTI_DRIVE;
+
+ if (at91_mux_get_pullup(pio, pin))
+ *config |= PULL_UP;
+
+ if (info->ops->get_deglitch && info->ops->get_deglitch(pio, pin))
+ *config |= DEGLITCH;
+ if (info->ops->get_debounce && info->ops->get_debounce(pio, pin, &div))
+ *config |= DEBOUNCE | (div << DEBOUNCE_VAL_SHIFT);
+ if (info->ops->get_pulldown && info->ops->get_pulldown(pio, pin))
+ *config |= PULL_DOWN;
+ if (info->ops->get_schmitt_trig && info->ops->get_schmitt_trig(pio, pin))
+ *config |= DIS_SCHMIT;
+
+ return 0;
+}
+
+static int at91_pinconf_set(struct pinctrl_dev *pctldev,
+ unsigned pin_id, unsigned long config)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ unsigned mask;
+ void __iomem *pio;
+
+ dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, config);
+ pio = pin_to_controller(info, pin_to_bank(pin_id));
+ mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK);
+
+ if (config & PULL_UP && config & PULL_DOWN)
+ return -EINVAL;
+
+ at91_mux_set_pullup(pio, mask, config & PULL_UP);
+ at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE);
+ if (info->ops->set_deglitch)
+ info->ops->set_deglitch(pio, mask, config & DEGLITCH);
+ if (info->ops->set_debounce)
+ info->ops->set_debounce(pio, mask, config & DEBOUNCE,
+ (config & DEBOUNCE_VAL) >> DEBOUNCE_VAL_SHIFT);
+ if (info->ops->set_pulldown)
+ info->ops->set_pulldown(pio, mask, config & PULL_DOWN);
+ if (info->ops->disable_schmitt_trig && config & DIS_SCHMIT)
+ info->ops->disable_schmitt_trig(pio, mask);
+
+ return 0;
+}
+
+static void at91_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned pin_id)
+{
+
+}
+
+static void at91_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned group)
+{
+}
+
+static struct pinconf_ops at91_pinconf_ops = {
+ .pin_config_get = at91_pinconf_get,
+ .pin_config_set = at91_pinconf_set,
+ .pin_config_dbg_show = at91_pinconf_dbg_show,
+ .pin_config_group_dbg_show = at91_pinconf_group_dbg_show,
+};
+
+static struct pinctrl_desc at91_pinctrl_desc = {
+ .pctlops = &at91_pctrl_ops,
+ .pmxops = &at91_pmx_ops,
+ .confops = &at91_pinconf_ops,
+ .owner = THIS_MODULE,
+};
+
+static const char *gpio_compat = "atmel,at91rm9200-gpio";
+
+static void __devinit at91_pinctrl_child_count(struct at91_pinctrl *info,
+ struct device_node *np)
+{
+ struct device_node *child;
+
+ for_each_child_of_node(np, child) {
+ if (of_device_is_compatible(child, gpio_compat)) {
+ info->nbanks++;
+ } else {
+ info->nfunctions++;
+ info->ngroups += of_get_child_count(child);
+ }
+ }
+}
+
+static int __devinit at91_pinctrl_mux_mask(struct at91_pinctrl *info,
+ struct device_node *np)
+{
+ int ret = 0;
+ int size;
+ const const __be32 *list;
+
+ list = of_get_property(np, "atmel,mux-mask", &size);
+ if (!list) {
+ dev_err(info->dev, "can not read the mux-mask of %d\n", size);
+ return -EINVAL;
+ }
+
+ size /= sizeof(*list);
+ if (!size || size % info->nbanks) {
+ dev_err(info->dev, "wrong mux mask array should be by %d\n", info->nbanks);
+ return -EINVAL;
+ }
+ info->nmux = size / info->nbanks;
+
+ info->mux_mask = devm_kzalloc(info->dev, sizeof(u32) * size, GFP_KERNEL);
+ if (!info->mux_mask) {
+ dev_err(info->dev, "could not alloc mux_mask\n");
+ return -ENOMEM;
+ }
+
+ ret = of_property_read_u32_array(np, "atmel,mux-mask",
+ info->mux_mask, size);
+ if (ret)
+ dev_err(info->dev, "can not read the mux-mask of %d\n", size);
+ return ret;
+}
+
+static int __devinit at91_pinctrl_parse_groups(struct device_node *np,
+ struct at91_pin_group *grp,
+ struct at91_pinctrl *info,
+ u32 index)
+{
+ struct at91_pmx_pin *pin;
+ int size;
+ const const __be32 *list;
+ int i, j;
+
+ dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
+
+ /* Initialise group */
+ grp->name = np->name;
+
+ /*
+ * the binding format is atmel,pins = <bank pin mux CONFIG ...>,
+ * do sanity check and calculate pins number
+ */
+ list = of_get_property(np, "atmel,pins", &size);
+ /* we do not check return since it's safe node passed down */
+ size /= sizeof(*list);
+ if (!size || size % 4) {
+ dev_err(info->dev, "wrong pins number or pins and configs should be by 4\n");
+ return -EINVAL;
+ }
+
+ grp->npins = size / 4;
+ pin = grp->pins_conf = devm_kzalloc(info->dev, grp->npins * sizeof(struct at91_pmx_pin),
+ GFP_KERNEL);
+ grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
+ GFP_KERNEL);
+ if (!grp->pins_conf || !grp->pins)
+ return -ENOMEM;
+
+ for (i = 0, j = 0; i < size; i += 4, j++) {
+ pin->bank = be32_to_cpu(*list++);
+ pin->pin = be32_to_cpu(*list++);
+ grp->pins[j] = pin->bank * MAX_NB_GPIO_PER_BANK + pin->pin;
+ pin->mux = be32_to_cpu(*list++);
+ pin->conf = be32_to_cpu(*list++);
+
+ at91_pin_dbg(info->dev, pin);
+ pin++;
+ }
+
+ return 0;
+}
+
+static int __devinit at91_pinctrl_parse_functions(struct device_node *np,
+ struct at91_pinctrl *info, u32 index)
+{
+ struct device_node *child;
+ struct at91_pmx_func *func;
+ struct at91_pin_group *grp;
+ int ret;
+ static u32 grp_index;
+ u32 i = 0;
+
+ dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
+
+ func = &info->functions[index];
+
+ /* Initialise function */
+ func->name = np->name;
+ func->ngroups = of_get_child_count(np);
+ if (func->ngroups <= 0) {
+ dev_err(info->dev, "no groups defined\n");
+ return -EINVAL;
+ }
+ func->groups = devm_kzalloc(info->dev,
+ func->ngroups * sizeof(char *), GFP_KERNEL);
+ if (!func->groups)
+ return -ENOMEM;
+
+ for_each_child_of_node(np, child) {
+ func->groups[i] = child->name;
+ grp = &info->groups[grp_index++];
+ ret = at91_pinctrl_parse_groups(child, grp, info, i++);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct of_device_id at91_pinctrl_of_match[] __devinitdata = {
+ { .compatible = "atmel,at91sam9x5-pinctrl", .data = &at91sam9x5_ops },
+ { .compatible = "atmel,at91rm9200-pinctrl", .data = &at91rm9200_ops },
+ { /* sentinel */ }
+};
+
+static int __devinit at91_pinctrl_probe_dt(struct platform_device *pdev,
+ struct at91_pinctrl *info)
+{
+ int ret = 0;
+ int i, j;
+ uint32_t *tmp;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *child;
+
+ if (!np)
+ return -ENODEV;
+
+ info->dev = &pdev->dev;
+ info->ops = (struct at91_pinctrl_mux_ops*)
+ of_match_device(at91_pinctrl_of_match, &pdev->dev)->data;
+ at91_pinctrl_child_count(info, np);
+
+ if (info->nbanks < 1) {
+ dev_err(&pdev->dev, "you need to specify atleast one gpio-controller\n");
+ return -EINVAL;
+ }
+
+ ret = at91_pinctrl_mux_mask(info, np);
+ if (ret)
+ return ret;
+
+ dev_dbg(&pdev->dev, "nmux = %d\n", info->nmux);
+
+ dev_dbg(&pdev->dev, "mux-mask\n");
+ tmp = info->mux_mask;
+ for (i = 0; i < info->nbanks; i++) {
+ for (j = 0; j < info->nmux; j++, tmp++) {
+ dev_dbg(&pdev->dev, "%d:%d\t0x%x\n", i, j, tmp[0]);
+ }
+ }
+
+ dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
+ dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups);
+ info->functions = devm_kzalloc(&pdev->dev, info->nfunctions * sizeof(struct at91_pmx_func),
+ GFP_KERNEL);
+ if (!info->functions)
+ return -ENOMEM;
+
+ info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct at91_pin_group),
+ GFP_KERNEL);
+ if (!info->groups)
+ return -ENOMEM;
+
+ dev_dbg(&pdev->dev, "nbanks = %d\n", info->nbanks);
+ dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
+ dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups);
+
+ i = 0;
+
+ for_each_child_of_node(np, child) {
+ if (of_device_is_compatible(child, gpio_compat))
+ continue;
+ ret = at91_pinctrl_parse_functions(child, info, i++);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to parse function\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int __devinit at91_pinctrl_probe(struct platform_device *pdev)
+{
+ struct at91_pinctrl *info;
+ struct pinctrl_pin_desc *pdesc;
+ int ret, i, j ,k;
+
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ ret = at91_pinctrl_probe_dt(pdev, info);
+ if (ret)
+ return ret;
+
+ /*
+ * We need all the GPIO drivers to probe FIRST, or we will not be able
+ * to obtain references to the struct gpio_chip * for them, and we
+ * need this to proceed.
+ */
+ for (i = 0; i < info->nbanks; i++) {
+ if (!gpio_chips[i]) {
+ dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i);
+ devm_kfree(&pdev->dev, info);
+ return -EPROBE_DEFER;
+ }
+ }
+
+ at91_pinctrl_desc.name = dev_name(&pdev->dev);
+ at91_pinctrl_desc.npins = info->nbanks * MAX_NB_GPIO_PER_BANK;
+ at91_pinctrl_desc.pins = pdesc =
+ devm_kzalloc(&pdev->dev, sizeof(*pdesc) * at91_pinctrl_desc.npins, GFP_KERNEL);
+
+ if (!at91_pinctrl_desc.pins)
+ return -ENOMEM;
+
+ for (i = 0 , k = 0; i < info->nbanks; i++) {
+ for (j = 0; j < MAX_NB_GPIO_PER_BANK; j++, k++) {
+ pdesc->number = k;
+ pdesc->name = kasprintf(GFP_KERNEL, "pio%c%d", i + 'A', j);
+ pdesc++;
+ }
+ }
+
+ platform_set_drvdata(pdev, info);
+ info->pctl = pinctrl_register(&at91_pinctrl_desc, &pdev->dev, info);
+
+ if (!info->pctl) {
+ dev_err(&pdev->dev, "could not register AT91 pinctrl driver\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* We will handle a range of GPIO pins */
+ for (i = 0; i < info->nbanks; i++)
+ pinctrl_add_gpio_range(info->pctl, &gpio_chips[i]->range);
+
+ dev_info(&pdev->dev, "initialized AT91 pinctrl driver\n");
+
+ return 0;
+
+err:
+ return ret;
+}
+
+static int __devexit at91_pinctrl_remove(struct platform_device *pdev)
+{
+ struct at91_pinctrl *info = platform_get_drvdata(pdev);
+
+ pinctrl_unregister(info->pctl);
+
+ return 0;
+}
+
+static int at91_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ /*
+ * Map back to global GPIO space and request muxing, the direction
+ * parameter does not matter for this controller.
+ */
+ int gpio = chip->base + offset;
+ int bank = chip->base / chip->ngpio;
+
+ dev_dbg(chip->dev, "%s:%d pio%c%d(%d)\n", __func__, __LINE__,
+ 'A' + bank, offset, gpio);
+
+ return pinctrl_request_gpio(gpio);
+}
+
+static void at91_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ int gpio = chip->base + offset;
+
+ pinctrl_free_gpio(gpio);
+}
+
+static int at91_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << offset;
+
+ writel_relaxed(mask, pio + PIO_ODR);
+ return 0;
+}
+
+static int at91_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << offset;
+ u32 pdsr;
+
+ pdsr = readl_relaxed(pio + PIO_PDSR);
+ return (pdsr & mask) != 0;
+}
+
+static void at91_gpio_set(struct gpio_chip *chip, unsigned offset,
+ int val)
+{
+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << offset;
+
+ writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR));
+}
+
+static int at91_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int val)
+{
+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << offset;
+
+ writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR));
+ writel_relaxed(mask, pio + PIO_OER);
+
+ return 0;
+}
+
+static int at91_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ int virq;
+
+ if (offset < chip->ngpio)
+ virq = irq_create_mapping(at91_gpio->domain, offset);
+ else
+ virq = -ENXIO;
+
+ dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
+ chip->label, offset + chip->base, virq);
+ return virq;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ enum at91_mux mode;
+ int i;
+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ void __iomem *pio = at91_gpio->regbase;
+
+ for (i = 0; i < chip->ngpio; i++) {
+ unsigned pin = chip->base + i;
+ unsigned mask = pin_to_mask(pin);
+ const char *gpio_label;
+ u32 pdsr;
+
+ gpio_label = gpiochip_is_requested(chip, i);
+ if (!gpio_label)
+ continue;
+ mode = at91_gpio->ops->get_periph(pio, mask);
+ seq_printf(s, "[%s] GPIO%s%d: ",
+ gpio_label, chip->label, i);
+ if (mode == AT91_MUX_GPIO) {
+ pdsr = readl_relaxed(pio + PIO_PDSR);
+
+ seq_printf(s, "[gpio] %s\n",
+ pdsr & mask ?
+ "set" : "clear");
+ } else {
+ seq_printf(s, "[periph %c]\n",
+ mode + 'A' - 1);
+ }
+ }
+}
+#else
+#define at91_gpio_dbg_show NULL
+#endif
+
+/* Several AIC controller irqs are dispatched through this GPIO handler.
+ * To use any AT91_PIN_* as an externally triggered IRQ, first call
+ * at91_set_gpio_input() then maybe enable its glitch filter.
+ * Then just request_irq() with the pin ID; it works like any ARM IRQ
+ * handler.
+ * First implementation always triggers on rising and falling edges
+ * whereas the newer PIO3 can be additionally configured to trigger on
+ * level, edge with any polarity.
+ *
+ * Alternatively, certain pins may be used directly as IRQ0..IRQ6 after
+ * configuring them with at91_set_a_periph() or at91_set_b_periph().
+ * IRQ0..IRQ6 should be configurable, e.g. level vs edge triggering.
+ */
+
+static void gpio_irq_mask(struct irq_data *d)
+{
+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << d->hwirq;
+
+ if (pio)
+ writel_relaxed(mask, pio + PIO_IDR);
+}
+
+static void gpio_irq_unmask(struct irq_data *d)
+{
+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << d->hwirq;
+
+ if (pio)
+ writel_relaxed(mask, pio + PIO_IER);
+}
+
+static int gpio_irq_type(struct irq_data *d, unsigned type)
+{
+ switch (type) {
+ case IRQ_TYPE_NONE:
+ case IRQ_TYPE_EDGE_BOTH:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/* Alternate irq type for PIO3 support */
+static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
+{
+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << d->hwirq;
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ writel_relaxed(mask, pio + PIO_ESR);
+ writel_relaxed(mask, pio + PIO_REHLSR);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ writel_relaxed(mask, pio + PIO_ESR);
+ writel_relaxed(mask, pio + PIO_FELLSR);
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ writel_relaxed(mask, pio + PIO_LSR);
+ writel_relaxed(mask, pio + PIO_FELLSR);
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ writel_relaxed(mask, pio + PIO_LSR);
+ writel_relaxed(mask, pio + PIO_REHLSR);
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ /*
+ * disable additional interrupt modes:
+ * fall back to default behavior
+ */
+ writel_relaxed(mask, pio + PIO_AIMDR);
+ return 0;
+ case IRQ_TYPE_NONE:
+ default:
+ pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq));
+ return -EINVAL;
+ }
+
+ /* enable additional interrupt modes */
+ writel_relaxed(mask, pio + PIO_AIMER);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
+{
+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+ unsigned bank = at91_gpio->pioc_idx;
+
+ if (unlikely(bank >= MAX_GPIO_BANKS))
+ return -EINVAL;
+
+ irq_set_irq_wake(at91_gpio->pioc_virq, state);
+
+ return 0;
+}
+#else
+#define gpio_irq_set_wake NULL
+#endif
+
+static struct irq_chip gpio_irqchip = {
+ .name = "GPIO",
+ .irq_disable = gpio_irq_mask,
+ .irq_mask = gpio_irq_mask,
+ .irq_unmask = gpio_irq_unmask,
+ /* .irq_set_type is set dynamically */
+ .irq_set_wake = gpio_irq_set_wake,
+};
+
+static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct irq_data *idata = irq_desc_get_irq_data(desc);
+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned long isr;
+ int n;
+
+ chained_irq_enter(chip, desc);
+ for (;;) {
+ /* Reading ISR acks pending (edge triggered) GPIO interrupts.
+ * When there none are pending, we're finished unless we need
+ * to process multiple banks (like ID_PIOCDE on sam9263).
+ */
+ isr = readl_relaxed(pio + PIO_ISR) & readl_relaxed(pio + PIO_IMR);
+ if (!isr) {
+ if (!at91_gpio->next)
+ break;
+ at91_gpio = at91_gpio->next;
+ pio = at91_gpio->regbase;
+ continue;
+ }
+
+ for_each_set_bit(n, &isr, BITS_PER_LONG) {
+ generic_handle_irq(irq_find_mapping(at91_gpio->domain, n));
+ }
+ }
+ chained_irq_exit(chip, desc);
+ /* now it may re-trigger */
+}
+
+/*
+ * This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parents, so it won't report false recursion.
+ */
+static struct lock_class_key gpio_lock_class;
+
+static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct at91_gpio_chip *at91_gpio = h->host_data;
+
+ irq_set_lockdep_class(virq, &gpio_lock_class);
+
+ /*
+ * Can use the "simple" and not "edge" handler since it's
+ * shorter, and the AIC handles interrupts sanely.
+ */
+ irq_set_chip_and_handler(virq, &gpio_irqchip,
+ handle_simple_irq);
+ set_irq_flags(virq, IRQF_VALID);
+ irq_set_chip_data(virq, at91_gpio);
+
+ return 0;
+}
+
+static int at91_gpio_irq_domain_xlate(struct irq_domain *d,
+ struct device_node *ctrlr,
+ const u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq,
+ unsigned int *out_type)
+{
+ struct at91_gpio_chip *at91_gpio = d->host_data;
+ int ret;
+ int pin = at91_gpio->chip.base + intspec[0];
+
+ if (WARN_ON(intsize < 2))
+ return -EINVAL;
+ *out_hwirq = intspec[0];
+ *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
+
+ ret = gpio_request(pin, ctrlr->full_name);
+ if (ret)
+ return ret;
+
+ ret = gpio_direction_input(pin);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct irq_domain_ops at91_gpio_ops = {
+ .map = at91_gpio_irq_map,
+ .xlate = at91_gpio_irq_domain_xlate,
+};
+
+static int at91_gpio_of_irq_setup(struct device_node *node,
+ struct at91_gpio_chip *at91_gpio)
+{
+ struct at91_gpio_chip *prev = NULL;
+ struct irq_data *d = irq_get_irq_data(at91_gpio->pioc_virq);
+
+ at91_gpio->pioc_hwirq = irqd_to_hwirq(d);
+
+ /* Setup proper .irq_set_type function */
+ gpio_irqchip.irq_set_type = at91_gpio->ops->irq_type;
+
+ /* Disable irqs of this PIO controller */
+ writel_relaxed(~0, at91_gpio->regbase + PIO_IDR);
+
+ /* Setup irq domain */
+ at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio,
+ &at91_gpio_ops, at91_gpio);
+ if (!at91_gpio->domain)
+ panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n",
+ at91_gpio->pioc_idx);
+
+ /* Setup chained handler */
+ if (at91_gpio->pioc_idx)
+ prev = gpio_chips[at91_gpio->pioc_idx - 1];
+
+ /* The toplevel handler handles one bank of GPIOs, except
+ * on some SoC it can handles up to three...
+ * We only set up the handler for the first of the list.
+ */
+ if (prev && prev->next == at91_gpio)
+ return 0;
+
+ irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio);
+ irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler);
+
+ return 0;
+}
+
+/* This structure is replicated for each GPIO block allocated at probe time */
+static struct gpio_chip at91_gpio_template = {
+ .request = at91_gpio_request,
+ .free = at91_gpio_free,
+ .direction_input = at91_gpio_direction_input,
+ .get = at91_gpio_get,
+ .direction_output = at91_gpio_direction_output,
+ .set = at91_gpio_set,
+ .to_irq = at91_gpio_to_irq,
+ .dbg_show = at91_gpio_dbg_show,
+ .can_sleep = 0,
+ .ngpio = MAX_NB_GPIO_PER_BANK,
+};
+
+static void __devinit at91_gpio_probe_fixup(void)
+{
+ unsigned i;
+ struct at91_gpio_chip *at91_gpio, *last = NULL;
+
+ for (i = 0; i < gpio_banks; i++) {
+ at91_gpio = gpio_chips[i];
+
+ /*
+ * GPIO controller are grouped on some SoC:
+ * PIOC, PIOD and PIOE can share the same IRQ line
+ */
+ if (last && last->pioc_virq == at91_gpio->pioc_virq)
+ last->next = at91_gpio;
+ last = at91_gpio;
+ }
+}
+
+static struct of_device_id at91_gpio_of_match[] __devinitdata = {
+ { .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops, },
+ { .compatible = "atmel,at91rm9200-gpio", .data = &at91rm9200_ops },
+ { /* sentinel */ }
+};
+
+static int __devinit at91_gpio_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res;
+ struct at91_gpio_chip *at91_chip = NULL;
+ struct gpio_chip *chip;
+ struct pinctrl_gpio_range *range;
+ int ret = 0;
+ int irq, i;
+ int alias_idx = of_alias_get_id(np, "gpio");
+ uint32_t ngpio;
+ char **names;
+
+ BUG_ON(alias_idx >= ARRAY_SIZE(gpio_chips));
+ if (gpio_chips[alias_idx]) {
+ ret = -EBUSY;
+ goto err;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENOENT;
+ goto err;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = irq;
+ goto err;
+ }
+
+ at91_chip = devm_kzalloc(&pdev->dev, sizeof(*at91_chip), GFP_KERNEL);
+ if (!at91_chip) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ at91_chip->regbase = devm_request_and_ioremap(&pdev->dev, res);
+ if (!at91_chip->regbase) {
+ dev_err(&pdev->dev, "failed to map registers, ignoring.\n");
+ ret = -EBUSY;
+ goto err;
+ }
+
+ at91_chip->ops = (struct at91_pinctrl_mux_ops*)
+ of_match_device(at91_gpio_of_match, &pdev->dev)->data;
+ at91_chip->pioc_virq = irq;
+ at91_chip->pioc_idx = alias_idx;
+
+ at91_chip->clock = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(at91_chip->clock)) {
+ dev_err(&pdev->dev, "failed to get clock, ignoring.\n");
+ goto err;
+ }
+
+ if (clk_prepare(at91_chip->clock))
+ goto clk_prep_err;
+
+ /* enable PIO controller's clock */
+ if (clk_enable(at91_chip->clock)) {
+ dev_err(&pdev->dev, "failed to enable clock, ignoring.\n");
+ goto clk_err;
+ }
+
+ at91_chip->chip = at91_gpio_template;
+
+ chip = &at91_chip->chip;
+ chip->of_node = np;
+ chip->label = dev_name(&pdev->dev);
+ chip->dev = &pdev->dev;
+ chip->owner = THIS_MODULE;
+ chip->base = alias_idx * MAX_NB_GPIO_PER_BANK;
+
+ if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) {
+ if (ngpio >= MAX_NB_GPIO_PER_BANK)
+ pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n",
+ alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK);
+ else
+ chip->ngpio = ngpio;
+ }
+
+ names = devm_kzalloc(&pdev->dev, sizeof(char*) * chip->ngpio, GFP_KERNEL);
+
+ if (!names) {
+ ret = -ENOMEM;
+ goto clk_err;
+ }
+
+ for (i = 0; i < chip->ngpio; i++)
+ names[i] = kasprintf(GFP_KERNEL, "pio%c%d", alias_idx + 'A', i);
+
+ chip->names = (const char*const*)names;
+
+ range = &at91_chip->range;
+ range->name = chip->label;
+ range->id = alias_idx;
+ range->pin_base = range->base = range->id * MAX_NB_GPIO_PER_BANK;
+
+ range->npins = chip->ngpio;
+ range->gc = chip;
+
+ ret = gpiochip_add(chip);
+ if (ret)
+ goto clk_err;
+
+ gpio_chips[alias_idx] = at91_chip;
+ gpio_banks = max(gpio_banks, alias_idx + 1);
+
+ at91_gpio_probe_fixup();
+
+ at91_gpio_of_irq_setup(np, at91_chip);
+
+ dev_info(&pdev->dev, "at address %p\n", at91_chip->regbase);
+
+ return 0;
+
+clk_err:
+ clk_unprepare(at91_chip->clock);
+clk_prep_err:
+ clk_put(at91_chip->clock);
+err:
+ dev_err(&pdev->dev, "Failure %i for GPIO %i\n", ret, alias_idx);
+
+ return ret;
+}
+
+static struct platform_driver at91_gpio_driver = {
+ .driver = {
+ .name = "gpio-at91",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(at91_gpio_of_match),
+ },
+ .probe = at91_gpio_probe,
+};
+
+static struct platform_driver at91_pinctrl_driver = {
+ .driver = {
+ .name = "pinctrl-at91",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(at91_pinctrl_of_match),
+ },
+ .probe = at91_pinctrl_probe,
+ .remove = __devexit_p(at91_pinctrl_remove),
+};
+
+static int __init at91_pinctrl_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&at91_gpio_driver);
+ if (ret)
+ return ret;
+ return platform_driver_register(&at91_pinctrl_driver);
+}
+arch_initcall(at91_pinctrl_init);
+
+static void __exit at91_pinctrl_exit(void)
+{
+ platform_driver_unregister(&at91_pinctrl_driver);
+}
+
+module_exit(at91_pinctrl_exit);
+MODULE_AUTHOR("Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>");
+MODULE_DESCRIPTION("Atmel AT91 pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c
index 7e9be18ec2d2..9a963edd66d1 100644
--- a/drivers/pinctrl/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/pinctrl-bcm2835.c
@@ -916,7 +916,7 @@ static int bcm2835_pinconf_set(struct pinctrl_dev *pctldev,
return 0;
}
-struct pinconf_ops bcm2835_pinconf_ops = {
+static struct pinconf_ops bcm2835_pinconf_ops = {
.pin_config_get = bcm2835_pinconf_get,
.pin_config_set = bcm2835_pinconf_set,
};
diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c
index b446c9641212..fbb37154471c 100644
--- a/drivers/pinctrl/pinctrl-coh901.c
+++ b/drivers/pinctrl/pinctrl-coh901.c
@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/io.h>
+#include <linux/irqdomain.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/platform_device.h>
@@ -64,10 +65,8 @@ struct u300_gpio {
struct gpio_chip chip;
struct list_head port_list;
struct clk *clk;
- struct resource *memres;
void __iomem *base;
struct device *dev;
- int irq_base;
u32 stride;
/* Register offsets */
u32 pcr;
@@ -83,6 +82,7 @@ struct u300_gpio_port {
struct list_head node;
struct u300_gpio *gpio;
char name[8];
+ struct irq_domain *domain;
int irq;
int number;
u8 toggle_edge_mode;
@@ -314,10 +314,30 @@ static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct u300_gpio *gpio = to_u300_gpio(chip);
- int retirq = gpio->irq_base + offset;
+ int portno = offset >> 3;
+ struct u300_gpio_port *port = NULL;
+ struct list_head *p;
+ int retirq;
- dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d\n", offset,
- retirq);
+ list_for_each(p, &gpio->port_list) {
+ port = list_entry(p, struct u300_gpio_port, node);
+ if (port->number == portno)
+ break;
+ }
+ if (port == NULL) {
+ dev_err(gpio->dev, "could not locate port for GPIO %d IRQ\n",
+ offset);
+ return -EINVAL;
+ }
+
+ /*
+ * The local hwirqs on the port are the lower three bits, there
+ * are exactly 8 IRQs per port since they are 8-bit
+ */
+ retirq = irq_find_mapping(port->domain, (offset & 0x7));
+
+ dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d from port %d\n",
+ offset, retirq, port->number);
return retirq;
}
@@ -467,7 +487,7 @@ static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger)
{
struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
struct u300_gpio *gpio = port->gpio;
- int offset = d->irq - gpio->irq_base;
+ int offset = (port->number << 3) + d->hwirq;
u32 val;
if ((trigger & IRQF_TRIGGER_RISING) &&
@@ -503,10 +523,12 @@ static void u300_gpio_irq_enable(struct irq_data *d)
{
struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
struct u300_gpio *gpio = port->gpio;
- int offset = d->irq - gpio->irq_base;
+ int offset = (port->number << 3) + d->hwirq;
u32 val;
unsigned long flags;
+ dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n",
+ d->hwirq, port->name, offset);
local_irq_save(flags);
val = readl(U300_PIN_REG(offset, ien));
writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien));
@@ -517,7 +539,7 @@ static void u300_gpio_irq_disable(struct irq_data *d)
{
struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
struct u300_gpio *gpio = port->gpio;
- int offset = d->irq - gpio->irq_base;
+ int offset = (port->number << 3) + d->hwirq;
u32 val;
unsigned long flags;
@@ -555,8 +577,7 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
int irqoffset;
for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) {
- int pin_irq = gpio->irq_base + (port->number << 3)
- + irqoffset;
+ int pin_irq = irq_find_mapping(port->domain, irqoffset);
int offset = pinoffset + irqoffset;
dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n",
@@ -631,64 +652,86 @@ static inline void u300_gpio_free_ports(struct u300_gpio *gpio)
list_for_each_safe(p, n, &gpio->port_list) {
port = list_entry(p, struct u300_gpio_port, node);
list_del(&port->node);
+ if (port->domain)
+ irq_domain_remove(port->domain);
kfree(port);
}
}
+/*
+ * Here we map a GPIO in the local gpio_chip pin space to a pin in
+ * the local pinctrl pin space. The pin controller used is
+ * pinctrl-u300.
+ */
+struct coh901_pinpair {
+ unsigned int offset;
+ unsigned int pin_base;
+};
+
+#define COH901_PINRANGE(a, b) { .offset = a, .pin_base = b }
+
+static struct coh901_pinpair coh901_pintable[] = {
+ COH901_PINRANGE(10, 426),
+ COH901_PINRANGE(11, 180),
+ COH901_PINRANGE(12, 165), /* MS/MMC card insertion */
+ COH901_PINRANGE(13, 179),
+ COH901_PINRANGE(14, 178),
+ COH901_PINRANGE(16, 194),
+ COH901_PINRANGE(17, 193),
+ COH901_PINRANGE(18, 192),
+ COH901_PINRANGE(19, 191),
+ COH901_PINRANGE(20, 186),
+ COH901_PINRANGE(21, 185),
+ COH901_PINRANGE(22, 184),
+ COH901_PINRANGE(23, 183),
+ COH901_PINRANGE(24, 182),
+ COH901_PINRANGE(25, 181),
+};
+
static int __init u300_gpio_probe(struct platform_device *pdev)
{
struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev);
struct u300_gpio *gpio;
+ struct resource *memres;
int err = 0;
int portno;
u32 val;
u32 ifr;
int i;
- gpio = kzalloc(sizeof(struct u300_gpio), GFP_KERNEL);
- if (gpio == NULL) {
- dev_err(&pdev->dev, "failed to allocate memory\n");
+ gpio = devm_kzalloc(&pdev->dev, sizeof(struct u300_gpio), GFP_KERNEL);
+ if (gpio == NULL)
return -ENOMEM;
- }
gpio->chip = u300_gpio_chip;
gpio->chip.ngpio = plat->ports * U300_GPIO_PINS_PER_PORT;
- gpio->irq_base = plat->gpio_irq_base;
gpio->chip.dev = &pdev->dev;
gpio->chip.base = plat->gpio_base;
gpio->dev = &pdev->dev;
- /* Get GPIO clock */
- gpio->clk = clk_get(gpio->dev, NULL);
+ memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!memres) {
+ dev_err(gpio->dev, "could not get GPIO memory resource\n");
+ return -ENODEV;
+ }
+
+ gpio->base = devm_request_and_ioremap(&pdev->dev, memres);
+ if (!gpio->base) {
+ dev_err(gpio->dev, "could not get remap memory\n");
+ return -ENOMEM;
+ }
+
+ gpio->clk = devm_clk_get(gpio->dev, NULL);
if (IS_ERR(gpio->clk)) {
err = PTR_ERR(gpio->clk);
dev_err(gpio->dev, "could not get GPIO clock\n");
- goto err_no_clk;
+ return err;
}
+
err = clk_prepare_enable(gpio->clk);
if (err) {
dev_err(gpio->dev, "could not enable GPIO clock\n");
- goto err_no_clk_enable;
- }
-
- gpio->memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!gpio->memres) {
- dev_err(gpio->dev, "could not get GPIO memory resource\n");
- err = -ENODEV;
- goto err_no_resource;
- }
-
- if (!request_mem_region(gpio->memres->start,
- resource_size(gpio->memres),
- "GPIO Controller")) {
- err = -ENODEV;
- goto err_no_ioregion;
- }
-
- gpio->base = ioremap(gpio->memres->start, resource_size(gpio->memres));
- if (!gpio->base) {
- err = -ENOMEM;
- goto err_no_ioremap;
+ return err;
}
dev_info(gpio->dev,
@@ -732,18 +775,28 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
port->irq = platform_get_irq_byname(pdev,
port->name);
- dev_dbg(gpio->dev, "register IRQ %d for %s\n", port->irq,
+ dev_dbg(gpio->dev, "register IRQ %d for port %s\n", port->irq,
port->name);
+ port->domain = irq_domain_add_linear(pdev->dev.of_node,
+ U300_GPIO_PINS_PER_PORT,
+ &irq_domain_simple_ops,
+ port);
+ if (!port->domain) {
+ err = -ENOMEM;
+ goto err_no_domain;
+ }
+
irq_set_chained_handler(port->irq, u300_gpio_irq_handler);
irq_set_handler_data(port->irq, port);
/* For each GPIO pin set the unique IRQ handler */
for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) {
- int irqno = gpio->irq_base + (portno << 3) + i;
+ int irqno = irq_create_mapping(port->domain, i);
- dev_dbg(gpio->dev, "handler for IRQ %d on %s\n",
- irqno, port->name);
+ dev_dbg(gpio->dev, "GPIO%d on port %s gets IRQ %d\n",
+ gpio->chip.base + (port->number << 3) + i,
+ port->name, irqno);
irq_set_chip_and_handler(irqno, &u300_gpio_irqchip,
handle_simple_irq);
set_irq_flags(irqno, IRQF_VALID);
@@ -763,32 +816,31 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
goto err_no_chip;
}
- /* Spawn pin controller device as child of the GPIO, pass gpio chip */
- plat->pinctrl_device->dev.platform_data = &gpio->chip;
- err = platform_device_register(plat->pinctrl_device);
- if (err)
- goto err_no_pinctrl;
+ /*
+ * Add pinctrl pin ranges, the pin controller must be registered
+ * at this point
+ */
+ for (i = 0; i < ARRAY_SIZE(coh901_pintable); i++) {
+ struct coh901_pinpair *p = &coh901_pintable[i];
+
+ err = gpiochip_add_pin_range(&gpio->chip, "pinctrl-u300",
+ p->offset, p->pin_base, 1);
+ if (err)
+ goto err_no_range;
+ }
platform_set_drvdata(pdev, gpio);
return 0;
-err_no_pinctrl:
+err_no_range:
err = gpiochip_remove(&gpio->chip);
err_no_chip:
+err_no_domain:
err_no_port:
u300_gpio_free_ports(gpio);
- iounmap(gpio->base);
-err_no_ioremap:
- release_mem_region(gpio->memres->start, resource_size(gpio->memres));
-err_no_ioregion:
-err_no_resource:
clk_disable_unprepare(gpio->clk);
-err_no_clk_enable:
- clk_put(gpio->clk);
-err_no_clk:
- kfree(gpio);
- dev_info(&pdev->dev, "module ERROR:%d\n", err);
+ dev_err(&pdev->dev, "module ERROR:%d\n", err);
return err;
}
@@ -806,13 +858,8 @@ static int __exit u300_gpio_remove(struct platform_device *pdev)
return err;
}
u300_gpio_free_ports(gpio);
- iounmap(gpio->base);
- release_mem_region(gpio->memres->start,
- resource_size(gpio->memres));
clk_disable_unprepare(gpio->clk);
- clk_put(gpio->clk);
platform_set_drvdata(pdev, NULL);
- kfree(gpio);
return 0;
}
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index 21362f48d370..6ff665209a4c 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -36,6 +36,7 @@
/* list of external wakeup controllers supported */
static const struct of_device_id exynos_wkup_irq_ids[] = {
{ .compatible = "samsung,exynos4210-wakeup-eint", },
+ { }
};
static void exynos_gpio_irq_unmask(struct irq_data *irqd)
diff --git a/drivers/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c
index ee7305903470..8ed20e84cb02 100644
--- a/drivers/pinctrl/pinctrl-falcon.c
+++ b/drivers/pinctrl/pinctrl-falcon.c
@@ -322,7 +322,7 @@ static void falcon_pinconf_group_dbg_show(struct pinctrl_dev *pctrldev,
{
}
-struct pinconf_ops falcon_pinconf_ops = {
+static struct pinconf_ops falcon_pinconf_ops = {
.pin_config_get = falcon_pinconf_get,
.pin_config_set = falcon_pinconf_set,
.pin_config_group_get = falcon_pinconf_group_get,
diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c
index 63866d95357d..525a2c8644f6 100644
--- a/drivers/pinctrl/pinctrl-imx.c
+++ b/drivers/pinctrl/pinctrl-imx.c
@@ -71,7 +71,7 @@ static const struct imx_pin_reg *imx_find_pin_reg(
break;
}
- if (!pin_reg) {
+ if (i == info->npin_regs) {
dev_err(info->dev, "Pin(%s): unable to find pin reg map\n",
info->pins[pin].name);
return NULL;
@@ -397,7 +397,7 @@ static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
}
}
-struct pinconf_ops imx_pinconf_ops = {
+static struct pinconf_ops imx_pinconf_ops = {
.pin_config_get = imx_pinconf_get,
.pin_config_set = imx_pinconf_set,
.pin_config_dbg_show = imx_pinconf_dbg_show,
diff --git a/drivers/pinctrl/pinctrl-lantiq.c b/drivers/pinctrl/pinctrl-lantiq.c
index 07ba7682cf22..15f501d89026 100644
--- a/drivers/pinctrl/pinctrl-lantiq.c
+++ b/drivers/pinctrl/pinctrl-lantiq.c
@@ -46,8 +46,8 @@ static int ltq_get_group_pins(struct pinctrl_dev *pctrldev,
return 0;
}
-void ltq_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
- struct pinctrl_map *map, unsigned num_maps)
+static void ltq_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned num_maps)
{
int i;
@@ -128,10 +128,10 @@ static int ltq_pinctrl_dt_subnode_size(struct device_node *np)
return ret;
}
-int ltq_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
- struct device_node *np_config,
- struct pinctrl_map **map,
- unsigned *num_maps)
+static int ltq_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map,
+ unsigned *num_maps)
{
struct pinctrl_map *tmp;
struct device_node *np;
@@ -275,16 +275,6 @@ static int ltq_pmx_enable(struct pinctrl_dev *pctrldev,
return 0;
}
-static void ltq_pmx_disable(struct pinctrl_dev *pctrldev,
- unsigned func,
- unsigned group)
-{
- /*
- * Nothing to do here. However, pinconf_check_ops() requires this
- * callback to be defined.
- */
-}
-
static int ltq_pmx_gpio_request_enable(struct pinctrl_dev *pctrldev,
struct pinctrl_gpio_range *range,
unsigned pin)
@@ -312,7 +302,6 @@ static struct pinmux_ops ltq_pmx_ops = {
.get_function_name = ltq_pmx_func_name,
.get_function_groups = ltq_pmx_get_groups,
.enable = ltq_pmx_enable,
- .disable = ltq_pmx_disable,
.gpio_request_enable = ltq_pmx_gpio_request_enable,
};
diff --git a/drivers/pinctrl/pinctrl-mxs.c b/drivers/pinctrl/pinctrl-mxs.c
index 4ba4636b6a4a..3e7d4d63f8bf 100644
--- a/drivers/pinctrl/pinctrl-mxs.c
+++ b/drivers/pinctrl/pinctrl-mxs.c
@@ -319,7 +319,7 @@ static void mxs_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
seq_printf(s, "0x%lx", config);
}
-struct pinconf_ops mxs_pinconf_ops = {
+static struct pinconf_ops mxs_pinconf_ops = {
.pin_config_get = mxs_pinconf_get,
.pin_config_set = mxs_pinconf_set,
.pin_config_group_get = mxs_pinconf_group_get,
diff --git a/drivers/pinctrl/pinctrl-nomadik-db8500.c b/drivers/pinctrl/pinctrl-nomadik-db8500.c
index debaa75b0552..7d88ae352119 100644
--- a/drivers/pinctrl/pinctrl-nomadik-db8500.c
+++ b/drivers/pinctrl/pinctrl-nomadik-db8500.c
@@ -475,8 +475,10 @@ static const unsigned hsit_a_1_pins[] = { DB8500_PIN_AJ9, DB8500_PIN_AH9,
DB8500_PIN_AG9, DB8500_PIN_AG8, DB8500_PIN_AF8 };
static const unsigned hsit_a_2_pins[] = { DB8500_PIN_AJ9, DB8500_PIN_AH9,
DB8500_PIN_AG9, DB8500_PIN_AG8 };
-static const unsigned clkout_a_1_pins[] = { DB8500_PIN_AH7, DB8500_PIN_AJ6 };
-static const unsigned clkout_a_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 };
+static const unsigned clkout1_a_1_pins[] = { DB8500_PIN_AH7 };
+static const unsigned clkout1_a_2_pins[] = { DB8500_PIN_AG7 };
+static const unsigned clkout2_a_1_pins[] = { DB8500_PIN_AJ6 };
+static const unsigned clkout2_a_2_pins[] = { DB8500_PIN_AF7 };
static const unsigned usb_a_1_pins[] = { DB8500_PIN_AF28, DB8500_PIN_AE29,
DB8500_PIN_AD29, DB8500_PIN_AC29, DB8500_PIN_AD28, DB8500_PIN_AD26,
DB8500_PIN_AE26, DB8500_PIN_AG29, DB8500_PIN_AE27, DB8500_PIN_AD27,
@@ -592,7 +594,8 @@ static const unsigned stmmod_c_1_pins[] = { DB8500_PIN_C20, DB8500_PIN_B21,
DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24 };
static const unsigned usbsim_c_1_pins[] = { DB8500_PIN_D22 };
static const unsigned mc4rstn_c_1_pins[] = { DB8500_PIN_AF25 };
-static const unsigned clkout_c_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AH12 };
+static const unsigned clkout1_c_1_pins[] = { DB8500_PIN_AH13 };
+static const unsigned clkout2_c_1_pins[] = { DB8500_PIN_AH12 };
static const unsigned i2c3_c_1_pins[] = { DB8500_PIN_AG12, DB8500_PIN_AH11 };
static const unsigned spi0_c_1_pins[] = { DB8500_PIN_AH10, DB8500_PIN_AH9,
DB8500_PIN_AG9, DB8500_PIN_AG8 };
@@ -600,14 +603,66 @@ static const unsigned usbsim_c_2_pins[] = { DB8500_PIN_AF8 };
static const unsigned i2c3_c_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 };
/* Other C1 column */
+static const unsigned u2rx_oc1_1_pins[] = { DB8500_PIN_AB2 };
+static const unsigned stmape_oc1_1_pins[] = { DB8500_PIN_AA4, DB8500_PIN_Y4,
+ DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 };
+static const unsigned remap0_oc1_1_pins[] = { DB8500_PIN_E1 };
+static const unsigned remap1_oc1_1_pins[] = { DB8500_PIN_E2 };
+static const unsigned ptma9_oc1_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4,
+ DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3, DB8500_PIN_H2,
+ DB8500_PIN_J2, DB8500_PIN_H1 };
static const unsigned kp_oc1_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3,
DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6,
DB8500_PIN_D6, DB8500_PIN_B7 };
+static const unsigned rf_oc1_1_pins[] = { DB8500_PIN_D8, DB8500_PIN_D9 };
+static const unsigned hxclk_oc1_1_pins[] = { DB8500_PIN_D16 };
+static const unsigned uartmodrx_oc1_1_pins[] = { DB8500_PIN_B17 };
+static const unsigned uartmodtx_oc1_1_pins[] = { DB8500_PIN_C16 };
+static const unsigned stmmod_oc1_1_pins[] = { DB8500_PIN_C19, DB8500_PIN_C17,
+ DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19 };
+static const unsigned hxgpio_oc1_1_pins[] = { DB8500_PIN_D21, DB8500_PIN_D20,
+ DB8500_PIN_C20, DB8500_PIN_B21, DB8500_PIN_C21, DB8500_PIN_A22,
+ DB8500_PIN_B24, DB8500_PIN_C22 };
+static const unsigned rf_oc1_2_pins[] = { DB8500_PIN_C23, DB8500_PIN_D23 };
static const unsigned spi2_oc1_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12,
DB8500_PIN_AH12, DB8500_PIN_AH11 };
static const unsigned spi2_oc1_2_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AH12,
DB8500_PIN_AH11 };
+/* Other C2 column */
+static const unsigned sbag_oc2_1_pins[] = { DB8500_PIN_AA4, DB8500_PIN_AB2,
+ DB8500_PIN_Y4, DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 };
+static const unsigned etmr4_oc2_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4,
+ DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3, DB8500_PIN_H2,
+ DB8500_PIN_J2, DB8500_PIN_H1 };
+static const unsigned ptma9_oc2_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16,
+ DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17,
+ DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20,
+ DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21,
+ DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 };
+
+/* Other C3 column */
+static const unsigned stmmod_oc3_1_pins[] = { DB8500_PIN_AB2, DB8500_PIN_W2,
+ DB8500_PIN_W3, DB8500_PIN_V3, DB8500_PIN_V2 };
+static const unsigned stmmod_oc3_2_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4,
+ DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3 };
+static const unsigned uartmodrx_oc3_1_pins[] = { DB8500_PIN_H2 };
+static const unsigned uartmodtx_oc3_1_pins[] = { DB8500_PIN_J2 };
+static const unsigned etmr4_oc3_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16,
+ DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17,
+ DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20,
+ DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21,
+ DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 };
+
+/* Other C4 column */
+static const unsigned sbag_oc4_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4,
+ DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3, DB8500_PIN_H1 };
+static const unsigned hwobs_oc4_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16,
+ DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17,
+ DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20,
+ DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21,
+ DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 };
+
#define DB8500_PIN_GROUP(a,b) { .name = #a, .pins = a##_pins, \
.npins = ARRAY_SIZE(a##_pins), .altsetting = b }
@@ -639,6 +694,7 @@ static const struct nmk_pingroup nmk_db8500_groups[] = {
DB8500_PIN_GROUP(i2c0_a_1, NMK_GPIO_ALT_A),
DB8500_PIN_GROUP(ipgpio0_a_1, NMK_GPIO_ALT_A),
DB8500_PIN_GROUP(ipgpio1_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(kp_a_2, NMK_GPIO_ALT_A),
DB8500_PIN_GROUP(msp2sck_a_1, NMK_GPIO_ALT_A),
DB8500_PIN_GROUP(msp2_a_1, NMK_GPIO_ALT_A),
DB8500_PIN_GROUP(mc4_a_1, NMK_GPIO_ALT_A),
@@ -647,8 +703,10 @@ static const struct nmk_pingroup nmk_db8500_groups[] = {
DB8500_PIN_GROUP(hsir_a_1, NMK_GPIO_ALT_A),
DB8500_PIN_GROUP(hsit_a_1, NMK_GPIO_ALT_A),
DB8500_PIN_GROUP(hsit_a_2, NMK_GPIO_ALT_A),
- DB8500_PIN_GROUP(clkout_a_1, NMK_GPIO_ALT_A),
- DB8500_PIN_GROUP(clkout_a_2, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(clkout1_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(clkout1_a_2, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(clkout2_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(clkout2_a_2, NMK_GPIO_ALT_A),
DB8500_PIN_GROUP(usb_a_1, NMK_GPIO_ALT_A),
/* Altfunction B column */
DB8500_PIN_GROUP(trig_b_1, NMK_GPIO_ALT_B),
@@ -720,15 +778,41 @@ static const struct nmk_pingroup nmk_db8500_groups[] = {
DB8500_PIN_GROUP(stmmod_c_1, NMK_GPIO_ALT_C),
DB8500_PIN_GROUP(usbsim_c_1, NMK_GPIO_ALT_C),
DB8500_PIN_GROUP(mc4rstn_c_1, NMK_GPIO_ALT_C),
- DB8500_PIN_GROUP(clkout_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(clkout1_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(clkout2_c_1, NMK_GPIO_ALT_C),
DB8500_PIN_GROUP(i2c3_c_1, NMK_GPIO_ALT_C),
DB8500_PIN_GROUP(spi0_c_1, NMK_GPIO_ALT_C),
DB8500_PIN_GROUP(usbsim_c_2, NMK_GPIO_ALT_C),
DB8500_PIN_GROUP(i2c3_c_2, NMK_GPIO_ALT_C),
/* Other alt C1 column */
+ DB8500_PIN_GROUP(u2rx_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(stmape_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(remap0_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(remap1_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(ptma9_oc1_1, NMK_GPIO_ALT_C1),
DB8500_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(rf_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(hxclk_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(uartmodrx_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(uartmodtx_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(stmmod_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(hxgpio_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(rf_oc1_2, NMK_GPIO_ALT_C1),
DB8500_PIN_GROUP(spi2_oc1_1, NMK_GPIO_ALT_C1),
DB8500_PIN_GROUP(spi2_oc1_2, NMK_GPIO_ALT_C1),
+ /* Other alt C2 column */
+ DB8500_PIN_GROUP(sbag_oc2_1, NMK_GPIO_ALT_C2),
+ DB8500_PIN_GROUP(etmr4_oc2_1, NMK_GPIO_ALT_C2),
+ DB8500_PIN_GROUP(ptma9_oc2_1, NMK_GPIO_ALT_C2),
+ /* Other alt C3 column */
+ DB8500_PIN_GROUP(stmmod_oc3_1, NMK_GPIO_ALT_C3),
+ DB8500_PIN_GROUP(stmmod_oc3_2, NMK_GPIO_ALT_C3),
+ DB8500_PIN_GROUP(uartmodrx_oc3_1, NMK_GPIO_ALT_C3),
+ DB8500_PIN_GROUP(uartmodtx_oc3_1, NMK_GPIO_ALT_C3),
+ DB8500_PIN_GROUP(etmr4_oc3_1, NMK_GPIO_ALT_C3),
+ /* Other alt C4 column */
+ DB8500_PIN_GROUP(sbag_oc4_1, NMK_GPIO_ALT_C4),
+ DB8500_PIN_GROUP(hwobs_oc4_1, NMK_GPIO_ALT_C4),
};
/* We use this macro to define the groups applicable to a function */
@@ -742,7 +826,7 @@ DB8500_FUNC_GROUPS(u1, "u1rxtx_a_1", "u1ctsrts_a_1");
* only available on two pins in alternative function C
*/
DB8500_FUNC_GROUPS(u2, "u2rxtx_b_1", "u2rxtx_c_1", "u2ctsrts_c_1",
- "u2rxtx_c_2", "u2rxtx_c_3");
+ "u2rxtx_c_2", "u2rxtx_c_3", "u2rx_oc1_1");
DB8500_FUNC_GROUPS(ipi2c, "ipi2c_a_1", "ipi2c_a_2");
/*
* MSP0 can only be on a certain set of pins, but the TX/RX pins can be
@@ -757,7 +841,7 @@ DB8500_FUNC_GROUPS(msp1, "msp1txrx_a_1", "msp1_a_1", "msp1txrx_b_1");
DB8500_FUNC_GROUPS(lcdb, "lcdb_a_1");
DB8500_FUNC_GROUPS(lcd, "lcdvsi0_a_1", "lcdvsi1_a_1", "lcd_d0_d7_a_1",
"lcd_d8_d11_a_1", "lcd_d12_d23_a_1", "lcd_b_1");
-DB8500_FUNC_GROUPS(kp, "kp_a_1", "kp_b_1", "kp_b_2", "kp_c_1", "kp_oc1_1");
+DB8500_FUNC_GROUPS(kp, "kp_a_1", "kp_a_2", "kp_b_1", "kp_b_2", "kp_c_1", "kp_oc1_1");
DB8500_FUNC_GROUPS(mc2, "mc2_a_1", "mc2rstn_c_1");
DB8500_FUNC_GROUPS(ssp1, "ssp1_a_1");
DB8500_FUNC_GROUPS(ssp0, "ssp0_a_1");
@@ -773,7 +857,8 @@ DB8500_FUNC_GROUPS(msp2, "msp2sck_a_1", "msp2_a_1");
DB8500_FUNC_GROUPS(mc4, "mc4_a_1", "mc4rstn_c_1");
DB8500_FUNC_GROUPS(mc1, "mc1_a_1", "mc1_a_2", "mc1dir_a_1");
DB8500_FUNC_GROUPS(hsi, "hsir_a_1", "hsit_a_1", "hsit_a_2");
-DB8500_FUNC_GROUPS(clkout, "clkout_a_1", "clkout_a_2", "clkout_c_1");
+DB8500_FUNC_GROUPS(clkout, "clkout1_a_1", "clkout1_a_2", "clkout1_c_1",
+ "clkout2_a_1", "clkout2_a_2", "clkout2_c_1");
DB8500_FUNC_GROUPS(usb, "usb_a_1");
DB8500_FUNC_GROUPS(trig, "trig_b_1");
DB8500_FUNC_GROUPS(i2c4, "i2c4_b_1");
@@ -784,8 +869,10 @@ DB8500_FUNC_GROUPS(i2c2, "i2c2_b_1", "i2c2_b_2");
* so select one of each.
*/
DB8500_FUNC_GROUPS(uartmod, "uartmodtx_b_1", "uartmodrx_b_1", "uartmodrx_b_2",
- "uartmodrx_c_1", "uartmod_tx_c_1");
-DB8500_FUNC_GROUPS(stmmod, "stmmod_b_1", "stmmod_c_1");
+ "uartmodrx_c_1", "uartmod_tx_c_1", "uartmodrx_oc1_1",
+ "uartmodtx_oc1_1", "uartmodrx_oc3_1", "uartmodtx_oc3_1");
+DB8500_FUNC_GROUPS(stmmod, "stmmod_b_1", "stmmod_c_1", "stmmod_oc1_1",
+ "stmmod_oc3_1", "stmmod_oc3_2");
DB8500_FUNC_GROUPS(spi3, "spi3_b_1");
/* Select between CS0 on alt B or PS1 on alt C */
DB8500_FUNC_GROUPS(sm, "sm_b_1", "smcs0_b_1", "smcs1_b_1", "smcleale_c_1",
@@ -799,13 +886,19 @@ DB8500_FUNC_GROUPS(ipjtag, "ipjtag_c_1");
DB8500_FUNC_GROUPS(slim0, "slim0_c_1");
DB8500_FUNC_GROUPS(ms, "ms_c_1");
DB8500_FUNC_GROUPS(iptrigout, "iptrigout_c_1");
-DB8500_FUNC_GROUPS(stmape, "stmape_c_1", "stmape_c_2");
+DB8500_FUNC_GROUPS(stmape, "stmape_c_1", "stmape_c_2", "stmape_oc1_1");
DB8500_FUNC_GROUPS(mc5, "mc5_c_1");
DB8500_FUNC_GROUPS(usbsim, "usbsim_c_1", "usbsim_c_2");
DB8500_FUNC_GROUPS(i2c3, "i2c3_c_1", "i2c3_c_2");
DB8500_FUNC_GROUPS(spi0, "spi0_c_1");
DB8500_FUNC_GROUPS(spi2, "spi2_oc1_1", "spi2_oc1_2");
-
+DB8500_FUNC_GROUPS(remap, "remap0_oc1_1", "remap1_oc1_1");
+DB8500_FUNC_GROUPS(sbag, "sbag_oc2_1", "sbag_oc4_1");
+DB8500_FUNC_GROUPS(ptm, "ptma9_oc1_1", "ptma9_oc2_1");
+DB8500_FUNC_GROUPS(rf, "rf_oc1_1", "rf_oc1_2");
+DB8500_FUNC_GROUPS(hx, "hxclk_oc1_1", "hxgpio_oc1_1");
+DB8500_FUNC_GROUPS(etm, "etmr4_oc2_1", "etmr4_oc3_1");
+DB8500_FUNC_GROUPS(hwobs, "hwobs_oc4_1");
#define FUNCTION(fname) \
{ \
.name = #fname, \
@@ -858,6 +951,12 @@ static const struct nmk_function nmk_db8500_functions[] = {
FUNCTION(i2c3),
FUNCTION(spi0),
FUNCTION(spi2),
+ FUNCTION(remap),
+ FUNCTION(ptm),
+ FUNCTION(rf),
+ FUNCTION(hx),
+ FUNCTION(etm),
+ FUNCTION(hwobs),
};
static const struct prcm_gpiocr_altcx_pin_desc db8500_altcx_pins[] = {
diff --git a/drivers/pinctrl/pinctrl-nomadik-db8540.c b/drivers/pinctrl/pinctrl-nomadik-db8540.c
index 52fc30181f7e..bb6a4016322a 100644
--- a/drivers/pinctrl/pinctrl-nomadik-db8540.c
+++ b/drivers/pinctrl/pinctrl-nomadik-db8540.c
@@ -460,8 +460,10 @@ static const unsigned hsit_a_1_pins[] = { DB8540_PIN_B11, DB8540_PIN_B10,
DB8540_PIN_E10, DB8540_PIN_B12, DB8540_PIN_D10 };
static const unsigned hsit_a_2_pins[] = { DB8540_PIN_B11, DB8540_PIN_B10,
DB8540_PIN_E10, DB8540_PIN_B12 };
-static const unsigned clkout_a_1_pins[] = { DB8540_PIN_D11, DB8540_PIN_AJ6 };
-static const unsigned clkout_a_2_pins[] = { DB8540_PIN_B13, DB8540_PIN_C12 };
+static const unsigned clkout1_a_1_pins[] = { DB8540_PIN_D11 };
+static const unsigned clkout1_a_2_pins[] = { DB8540_PIN_B13 };
+static const unsigned clkout2_a_1_pins[] = { DB8540_PIN_AJ6 };
+static const unsigned clkout2_a_2_pins[] = { DB8540_PIN_C12 };
static const unsigned msp4_a_1_pins[] = { DB8540_PIN_B14, DB8540_PIN_E11 };
static const unsigned usb_a_1_pins[] = { DB8540_PIN_D12, DB8540_PIN_D15,
DB8540_PIN_C13, DB8540_PIN_C14, DB8540_PIN_C18, DB8540_PIN_C16,
@@ -698,8 +700,10 @@ static const struct nmk_pingroup nmk_db8540_groups[] = {
DB8540_PIN_GROUP(hsir_a_1, NMK_GPIO_ALT_A),
DB8540_PIN_GROUP(hsit_a_1, NMK_GPIO_ALT_A),
DB8540_PIN_GROUP(hsit_a_2, NMK_GPIO_ALT_A),
- DB8540_PIN_GROUP(clkout_a_1, NMK_GPIO_ALT_A),
- DB8540_PIN_GROUP(clkout_a_2, NMK_GPIO_ALT_A),
+ DB8540_PIN_GROUP(clkout1_a_1, NMK_GPIO_ALT_A),
+ DB8540_PIN_GROUP(clkout1_a_2, NMK_GPIO_ALT_A),
+ DB8540_PIN_GROUP(clkout2_a_1, NMK_GPIO_ALT_A),
+ DB8540_PIN_GROUP(clkout2_a_2, NMK_GPIO_ALT_A),
DB8540_PIN_GROUP(msp4_a_1, NMK_GPIO_ALT_A),
DB8540_PIN_GROUP(usb_a_1, NMK_GPIO_ALT_A),
/* Altfunction B column */
@@ -822,6 +826,7 @@ static const struct nmk_pingroup nmk_db8540_groups[] = {
DB8540_PIN_GROUP(modaccuarttxrx_oc4_1, NMK_GPIO_ALT_C4),
DB8540_PIN_GROUP(modaccuartrtscts_oc4_1, NMK_GPIO_ALT_C4),
DB8540_PIN_GROUP(stmmod_oc4_1, NMK_GPIO_ALT_C4),
+ DB8540_PIN_GROUP(moduartstmmux_oc4_1, NMK_GPIO_ALT_C4),
};
@@ -830,7 +835,8 @@ static const struct nmk_pingroup nmk_db8540_groups[] = {
static const char * const a##_groups[] = { b };
DB8540_FUNC_GROUPS(apetrig, "apetrig_b_1");
-DB8540_FUNC_GROUPS(clkout, "clkoutreq_a_1", "clkout_a_1", "clkout_a_2");
+DB8540_FUNC_GROUPS(clkout, "clkoutreq_a_1", "clkout1_a_1", "clkout1_a_2",
+ "clkout2_a_1", "clkout2_a_2");
DB8540_FUNC_GROUPS(ddrtrig, "ddrtrig_b_1");
DB8540_FUNC_GROUPS(hsi, "hsir_a_1", "hsit_a_1", "hsit_a_2");
DB8540_FUNC_GROUPS(hwobs, "hwobs_oc4_1");
diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c
index cf82d9ce4dee..8ef3e85cb011 100644
--- a/drivers/pinctrl/pinctrl-nomadik.c
+++ b/drivers/pinctrl/pinctrl-nomadik.c
@@ -30,26 +30,10 @@
#include <linux/pinctrl/pinconf.h>
/* Since we request GPIOs from ourself */
#include <linux/pinctrl/consumer.h>
-/*
- * For the U8500 archs, use the PRCMU register interface, for the older
- * Nomadik, provide some stubs. The functions using these will only be
- * called on the U8500 series.
- */
-#ifdef CONFIG_ARCH_U8500
-#include <linux/mfd/dbx500-prcmu.h>
-#else
-static inline u32 prcmu_read(unsigned int reg) {
- return 0;
-}
-static inline void prcmu_write(unsigned int reg, u32 value) {}
-static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value) {}
-#endif
+#include <linux/platform_data/pinctrl-nomadik.h>
#include <asm/mach/irq.h>
-#include <plat/pincfg.h>
-#include <plat/gpio-nomadik.h>
-
#include "pinctrl-nomadik.h"
/*
@@ -60,8 +44,6 @@ static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value) {}
* Symbols in this file are called "nmk_gpio" for "nomadik gpio"
*/
-#define NMK_GPIO_PER_CHIP 32
-
struct nmk_gpio_chip {
struct gpio_chip chip;
struct irq_domain *domain;
@@ -86,10 +68,18 @@ struct nmk_gpio_chip {
u32 lowemi;
};
+/**
+ * struct nmk_pinctrl - state container for the Nomadik pin controller
+ * @dev: containing device pointer
+ * @pctl: corresponding pin controller device
+ * @soc: SoC data for this specific chip
+ * @prcm_base: PRCM register range virtual base
+ */
struct nmk_pinctrl {
struct device *dev;
struct pinctrl_dev *pctl;
const struct nmk_pinctrl_soc_data *soc;
+ void __iomem *prcm_base;
};
static struct nmk_gpio_chip *
@@ -251,6 +241,15 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset)
dev_dbg(nmk_chip->chip.dev, "%d: clearing interrupt mask\n", gpio);
}
+static void nmk_write_masked(void __iomem *reg, u32 mask, u32 value)
+{
+ u32 val;
+
+ val = readl(reg);
+ val = ((val & ~mask) | (value & mask));
+ writel(val, reg);
+}
+
static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
unsigned offset, unsigned alt_num)
{
@@ -289,8 +288,8 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
if (pin_desc->altcx[i].used == true) {
reg = gpiocr_regs[pin_desc->altcx[i].reg_index];
bit = pin_desc->altcx[i].control_bit;
- if (prcmu_read(reg) & BIT(bit)) {
- prcmu_write_masked(reg, BIT(bit), 0);
+ if (readl(npct->prcm_base + reg) & BIT(bit)) {
+ nmk_write_masked(npct->prcm_base + reg, BIT(bit), 0);
dev_dbg(npct->dev,
"PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n",
offset, i+1);
@@ -318,8 +317,8 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
if (pin_desc->altcx[i].used == true) {
reg = gpiocr_regs[pin_desc->altcx[i].reg_index];
bit = pin_desc->altcx[i].control_bit;
- if (prcmu_read(reg) & BIT(bit)) {
- prcmu_write_masked(reg, BIT(bit), 0);
+ if (readl(npct->prcm_base + reg) & BIT(bit)) {
+ nmk_write_masked(npct->prcm_base + reg, BIT(bit), 0);
dev_dbg(npct->dev,
"PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n",
offset, i+1);
@@ -331,7 +330,7 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
bit = pin_desc->altcx[alt_index].control_bit;
dev_dbg(npct->dev, "PRCM GPIOCR: pin %i: alternate-C%i has been selected\n",
offset, alt_index+1);
- prcmu_write_masked(reg, BIT(bit), BIT(bit));
+ nmk_write_masked(npct->prcm_base + reg, BIT(bit), BIT(bit));
}
static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
@@ -536,7 +535,7 @@ static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep)
* and its sleep mode based on the specified configuration. The @cfg is
* usually one of the SoC specific macros defined in mach/<soc>-pins.h. These
* are constructed using, and can be further enhanced with, the macros in
- * plat/pincfg.h.
+ * <linux/platform_data/pinctrl-nomadik.h>
*
* If a pin's mode is set to GPIO, it is configured as an input to avoid
* side-effects. The gpio can be manipulated later using standard GPIO API
@@ -675,6 +674,35 @@ int nmk_gpio_set_mode(int gpio, int gpio_mode)
}
EXPORT_SYMBOL(nmk_gpio_set_mode);
+static int nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev, int gpio)
+{
+ int i;
+ u16 reg;
+ u8 bit;
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+ const struct prcm_gpiocr_altcx_pin_desc *pin_desc;
+ const u16 *gpiocr_regs;
+
+ for (i = 0; i < npct->soc->npins_altcx; i++) {
+ if (npct->soc->altcx_pins[i].pin == gpio)
+ break;
+ }
+ if (i == npct->soc->npins_altcx)
+ return NMK_GPIO_ALT_C;
+
+ pin_desc = npct->soc->altcx_pins + i;
+ gpiocr_regs = npct->soc->prcm_gpiocr_registers;
+ for (i = 0; i < PRCM_IDX_GPIOCR_ALTC_MAX; i++) {
+ if (pin_desc->altcx[i].used == true) {
+ reg = gpiocr_regs[pin_desc->altcx[i].reg_index];
+ bit = pin_desc->altcx[i].control_bit;
+ if (readl(npct->prcm_base + reg) & BIT(bit))
+ return NMK_GPIO_ALT_C+i+1;
+ }
+ }
+ return NMK_GPIO_ALT_C;
+}
+
int nmk_gpio_get_mode(int gpio)
{
struct nmk_gpio_chip *nmk_chip;
@@ -1063,8 +1091,9 @@ static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
#include <linux/seq_file.h>
-static void nmk_gpio_dbg_show_one(struct seq_file *s, struct gpio_chip *chip,
- unsigned offset, unsigned gpio)
+static void nmk_gpio_dbg_show_one(struct seq_file *s,
+ struct pinctrl_dev *pctldev, struct gpio_chip *chip,
+ unsigned offset, unsigned gpio)
{
const char *label = gpiochip_is_requested(chip, offset);
struct nmk_gpio_chip *nmk_chip =
@@ -1078,12 +1107,18 @@ static void nmk_gpio_dbg_show_one(struct seq_file *s, struct gpio_chip *chip,
[NMK_GPIO_ALT_A] = "altA",
[NMK_GPIO_ALT_B] = "altB",
[NMK_GPIO_ALT_C] = "altC",
+ [NMK_GPIO_ALT_C+1] = "altC1",
+ [NMK_GPIO_ALT_C+2] = "altC2",
+ [NMK_GPIO_ALT_C+3] = "altC3",
+ [NMK_GPIO_ALT_C+4] = "altC4",
};
clk_enable(nmk_chip->clk);
is_out = !!(readl(nmk_chip->addr + NMK_GPIO_DIR) & bit);
pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit);
mode = nmk_gpio_get_mode(gpio);
+ if ((mode == NMK_GPIO_ALT_C) && pctldev)
+ mode = nmk_prcm_gpiocr_get_mode(pctldev, gpio);
seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s",
gpio, label ?: "(none)",
@@ -1127,13 +1162,14 @@ static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
unsigned gpio = chip->base;
for (i = 0; i < chip->ngpio; i++, gpio++) {
- nmk_gpio_dbg_show_one(s, chip, i, gpio);
+ nmk_gpio_dbg_show_one(s, NULL, chip, i, gpio);
seq_printf(s, "\n");
}
}
#else
static inline void nmk_gpio_dbg_show_one(struct seq_file *s,
+ struct pinctrl_dev *pctldev,
struct gpio_chip *chip,
unsigned offset, unsigned gpio)
{
@@ -1250,8 +1286,8 @@ void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up)
}
}
-int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hwirq)
+static int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
{
struct nmk_gpio_chip *nmk_chip = d->host_data;
@@ -1464,7 +1500,7 @@ static void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
return;
}
chip = range->gc;
- nmk_gpio_dbg_show_one(s, chip, offset - chip->base, offset);
+ nmk_gpio_dbg_show_one(s, pctldev, chip, offset - chip->base, offset);
}
static struct pinctrl_ops nmk_pinctrl_ops = {
@@ -1635,9 +1671,9 @@ static void nmk_pmx_disable(struct pinctrl_dev *pctldev,
dev_dbg(npct->dev, "disable group %s, %u pins\n", g->name, g->npins);
}
-int nmk_gpio_request_enable(struct pinctrl_dev *pctldev,
- struct pinctrl_gpio_range *range,
- unsigned offset)
+static int nmk_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
{
struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
struct nmk_gpio_chip *nmk_chip;
@@ -1666,9 +1702,9 @@ int nmk_gpio_request_enable(struct pinctrl_dev *pctldev,
return 0;
}
-void nmk_gpio_disable_free(struct pinctrl_dev *pctldev,
- struct pinctrl_gpio_range *range,
- unsigned offset)
+static void nmk_gpio_disable_free(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
{
struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
@@ -1686,17 +1722,15 @@ static struct pinmux_ops nmk_pinmux_ops = {
.gpio_disable_free = nmk_gpio_disable_free,
};
-int nmk_pin_config_get(struct pinctrl_dev *pctldev,
- unsigned pin,
- unsigned long *config)
+static int nmk_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *config)
{
/* Not implemented */
return -EINVAL;
}
-int nmk_pin_config_set(struct pinctrl_dev *pctldev,
- unsigned pin,
- unsigned long config)
+static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long config)
{
static const char *pullnames[] = {
[NMK_GPIO_PULL_NONE] = "none",
@@ -1818,6 +1852,7 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev)
const struct platform_device_id *platid = platform_get_device_id(pdev);
struct device_node *np = pdev->dev.of_node;
struct nmk_pinctrl *npct;
+ struct resource *res;
unsigned int version = 0;
int i;
@@ -1827,9 +1862,14 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev)
if (platid)
version = platid->driver_data;
- else if (np)
- version = (unsigned int)
- of_match_device(nmk_pinctrl_match, &pdev->dev)->data;
+ else if (np) {
+ const struct of_device_id *match;
+
+ match = of_match_device(nmk_pinctrl_match, &pdev->dev);
+ if (!match)
+ return -ENODEV;
+ version = (unsigned int) match->data;
+ }
/* Poke in other ASIC variants here */
if (version == PINCTRL_NMK_STN8815)
@@ -1839,22 +1879,37 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev)
if (version == PINCTRL_NMK_DB8540)
nmk_pinctrl_db8540_init(&npct->soc);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res) {
+ npct->prcm_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!npct->prcm_base) {
+ dev_err(&pdev->dev,
+ "failed to ioremap PRCM registers\n");
+ return -ENOMEM;
+ }
+ } else {
+ dev_info(&pdev->dev,
+ "No PRCM base, assume no ALT-Cx control is available\n");
+ }
+
/*
* We need all the GPIO drivers to probe FIRST, or we will not be able
* to obtain references to the struct gpio_chip * for them, and we
* need this to proceed.
*/
for (i = 0; i < npct->soc->gpio_num_ranges; i++) {
- if (!nmk_gpio_chips[i]) {
+ if (!nmk_gpio_chips[npct->soc->gpio_ranges[i].id]) {
dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i);
return -EPROBE_DEFER;
}
- npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[i]->chip;
+ npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[npct->soc->gpio_ranges[i].id]->chip;
}
nmk_pinctrl_desc.pins = npct->soc->pins;
nmk_pinctrl_desc.npins = npct->soc->npins;
npct->dev = &pdev->dev;
+
npct->pctl = pinctrl_register(&nmk_pinctrl_desc, &pdev->dev, npct);
if (!npct->pctl) {
dev_err(&pdev->dev, "could not register Nomadik pinctrl driver\n");
@@ -1889,6 +1944,7 @@ static const struct platform_device_id nmk_pinctrl_id[] = {
{ "pinctrl-stn8815", PINCTRL_NMK_STN8815 },
{ "pinctrl-db8500", PINCTRL_NMK_DB8500 },
{ "pinctrl-db8540", PINCTRL_NMK_DB8540 },
+ { }
};
static struct platform_driver nmk_pinctrl_driver = {
diff --git a/drivers/pinctrl/pinctrl-nomadik.h b/drivers/pinctrl/pinctrl-nomadik.h
index eef316e979a0..bcd4191e10ea 100644
--- a/drivers/pinctrl/pinctrl-nomadik.h
+++ b/drivers/pinctrl/pinctrl-nomadik.h
@@ -1,7 +1,7 @@
#ifndef PINCTRL_PINCTRL_NOMADIK_H
#define PINCTRL_PINCTRL_NOMADIK_H
-#include <plat/gpio-nomadik.h>
+#include <linux/platform_data/pinctrl-nomadik.h>
/* Package definitions */
#define PINCTRL_NMK_STN8815 0
diff --git a/drivers/pinctrl/pinctrl-pxa3xx.c b/drivers/pinctrl/pinctrl-pxa3xx.c
index f14cd6ba4c0b..51f8a388b917 100644
--- a/drivers/pinctrl/pinctrl-pxa3xx.c
+++ b/drivers/pinctrl/pinctrl-pxa3xx.c
@@ -173,7 +173,6 @@ int pxa3xx_pinctrl_register(struct platform_device *pdev,
{
struct pinctrl_desc *desc;
struct resource *res;
- int ret = 0;
if (!info || !info->cputype)
return -EINVAL;
@@ -188,23 +187,17 @@ int pxa3xx_pinctrl_register(struct platform_device *pdev,
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENOENT;
- info->phy_base = res->start;
- info->phy_size = resource_size(res);
- info->virt_base = ioremap(info->phy_base, info->phy_size);
+ info->virt_base = devm_request_and_ioremap(&pdev->dev, res);
if (!info->virt_base)
return -ENOMEM;
info->pctrl = pinctrl_register(desc, &pdev->dev, info);
if (!info->pctrl) {
dev_err(&pdev->dev, "failed to register PXA pinmux driver\n");
- ret = -EINVAL;
- goto err;
+ return -EINVAL;
}
pinctrl_add_gpio_range(info->pctrl, &pxa3xx_pinctrl_gpio_range);
platform_set_drvdata(pdev, info);
return 0;
-err:
- iounmap(info->virt_base);
- return ret;
}
int pxa3xx_pinctrl_unregister(struct platform_device *pdev)
@@ -212,7 +205,6 @@ int pxa3xx_pinctrl_unregister(struct platform_device *pdev)
struct pxa3xx_pinmux_info *info = platform_get_drvdata(pdev);
pinctrl_unregister(info->pctrl);
- iounmap(info->virt_base);
platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/pinctrl/pinctrl-pxa3xx.h b/drivers/pinctrl/pinctrl-pxa3xx.h
index 8135744d6599..92fad0880834 100644
--- a/drivers/pinctrl/pinctrl-pxa3xx.h
+++ b/drivers/pinctrl/pinctrl-pxa3xx.h
@@ -60,8 +60,6 @@ struct pxa3xx_pinmux_info {
struct device *dev;
struct pinctrl_dev *pctrl;
enum pxa_cpu_type cputype;
- unsigned int phy_base;
- unsigned int phy_size;
void __iomem *virt_base;
struct pxa3xx_mfp_pin *mfp;
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 726a729a2ec9..554946356fba 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -30,6 +30,7 @@
#define PCS_MUX_BITS_NAME "pinctrl-single,bits"
#define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 1)
#define PCS_OFF_DISABLED ~0U
+#define PCS_MAX_GPIO_VALUES 2
/**
* struct pcs_pingroup - pingroups for a function
@@ -77,6 +78,16 @@ struct pcs_function {
};
/**
+ * struct pcs_gpio_range - pinctrl gpio range
+ * @range: subrange of the GPIO number space
+ * @gpio_func: gpio function value in the pinmux register
+ */
+struct pcs_gpio_range {
+ struct pinctrl_gpio_range range;
+ int gpio_func;
+};
+
+/**
* struct pcs_data - wrapper for data needed by pinctrl framework
* @pa: pindesc array
* @cur: index to current element
@@ -244,15 +255,15 @@ static int pcs_get_group_pins(struct pinctrl_dev *pctldev,
static void pcs_pin_dbg_show(struct pinctrl_dev *pctldev,
struct seq_file *s,
- unsigned offset)
+ unsigned pin)
{
struct pcs_device *pcs;
- unsigned val;
+ unsigned val, mux_bytes;
pcs = pinctrl_dev_get_drvdata(pctldev);
- val = pcs->read(pcs->base + offset);
- val &= pcs->fmask;
+ mux_bytes = pcs->width / BITS_PER_BYTE;
+ val = pcs->read(pcs->base + pin * mux_bytes);
seq_printf(s, "%08x %s " , val, DRIVER_NAME);
}
@@ -403,9 +414,26 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector,
}
static int pcs_request_gpio(struct pinctrl_dev *pctldev,
- struct pinctrl_gpio_range *range, unsigned offset)
+ struct pinctrl_gpio_range *range, unsigned pin)
{
- return -ENOTSUPP;
+ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+ struct pcs_gpio_range *gpio = NULL;
+ int end, mux_bytes;
+ unsigned data;
+
+ gpio = container_of(range, struct pcs_gpio_range, range);
+ end = range->pin_base + range->npins - 1;
+ if (pin < range->pin_base || pin > end) {
+ dev_err(pctldev->dev,
+ "pin %d isn't in the range of %d to %d\n",
+ pin, range->pin_base, end);
+ return -EINVAL;
+ }
+ mux_bytes = pcs->width / BITS_PER_BYTE;
+ data = pcs->read(pcs->base + pin * mux_bytes) & ~pcs->fmask;
+ data |= gpio->gpio_func;
+ pcs->write(data, pcs->base + pin * mux_bytes);
+ return 0;
}
static struct pinmux_ops pcs_pinmux_ops = {
@@ -772,7 +800,7 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
pcs = pinctrl_dev_get_drvdata(pctldev);
*map = devm_kzalloc(pcs->dev, sizeof(**map), GFP_KERNEL);
- if (!map)
+ if (!*map)
return -ENOMEM;
*num_maps = 0;
@@ -879,6 +907,50 @@ static void pcs_free_resources(struct pcs_device *pcs)
static struct of_device_id pcs_of_match[];
+static int __devinit pcs_add_gpio_range(struct device_node *node,
+ struct pcs_device *pcs)
+{
+ struct pcs_gpio_range *gpio;
+ struct device_node *child;
+ struct resource r;
+ const char name[] = "pinctrl-single";
+ u32 gpiores[PCS_MAX_GPIO_VALUES];
+ int ret, i = 0, mux_bytes = 0;
+
+ for_each_child_of_node(node, child) {
+ ret = of_address_to_resource(child, 0, &r);
+ if (ret < 0)
+ continue;
+ memset(gpiores, 0, sizeof(u32) * PCS_MAX_GPIO_VALUES);
+ ret = of_property_read_u32_array(child, "pinctrl-single,gpio",
+ gpiores, PCS_MAX_GPIO_VALUES);
+ if (ret < 0)
+ continue;
+ gpio = devm_kzalloc(pcs->dev, sizeof(*gpio), GFP_KERNEL);
+ if (!gpio) {
+ dev_err(pcs->dev, "failed to allocate pcs gpio\n");
+ return -ENOMEM;
+ }
+ gpio->range.name = devm_kzalloc(pcs->dev, sizeof(name),
+ GFP_KERNEL);
+ if (!gpio->range.name) {
+ dev_err(pcs->dev, "failed to allocate range name\n");
+ return -ENOMEM;
+ }
+ memcpy((char *)gpio->range.name, name, sizeof(name));
+
+ gpio->range.id = i++;
+ gpio->range.base = gpiores[0];
+ gpio->gpio_func = gpiores[1];
+ mux_bytes = pcs->width / BITS_PER_BYTE;
+ gpio->range.pin_base = (r.start - pcs->res->start) / mux_bytes;
+ gpio->range.npins = (r.end - r.start) / mux_bytes + 1;
+
+ pinctrl_add_gpio_range(pcs->pctl, &gpio->range);
+ }
+ return 0;
+}
+
static int __devinit pcs_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -975,6 +1047,10 @@ static int __devinit pcs_probe(struct platform_device *pdev)
goto free;
}
+ ret = pcs_add_gpio_range(np, pcs);
+ if (ret < 0)
+ goto free;
+
dev_info(pcs->dev, "%i pins at pa %p size %u\n",
pcs->desc.npins, pcs->base, pcs->size);
diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c
index 9ecacf3d0a75..a3905e58d1b3 100644
--- a/drivers/pinctrl/pinctrl-sirf.c
+++ b/drivers/pinctrl/pinctrl-sirf.c
@@ -32,10 +32,10 @@
#define SIRFSOC_NUM_PADS 622
#define SIRFSOC_RSC_PIN_MUX 0x4
-#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84)
+#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84)
+#define SIRFSOC_GPIO_PAD_EN_CLR(g) ((g)*0x100 + 0x90)
#define SIRFSOC_GPIO_CTRL(g, i) ((g)*0x100 + (i)*4)
#define SIRFSOC_GPIO_DSP_EN0 (0x80)
-#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84)
#define SIRFSOC_GPIO_INT_STATUS(g) ((g)*0x100 + 0x8C)
#define SIRFSOC_GPIO_CTL_INTR_LOW_MASK 0x1
@@ -60,6 +60,7 @@ struct sirfsoc_gpio_bank {
int id;
int parent_irq;
spinlock_t lock;
+ bool is_marco; /* for marco, some registers are different with prima2 */
};
static struct sirfsoc_gpio_bank sgpio_bank[SIRFSOC_GPIO_NO_OF_BANKS];
@@ -191,6 +192,7 @@ struct sirfsoc_pmx {
struct pinctrl_dev *pmx;
void __iomem *gpio_virtbase;
void __iomem *rsc_virtbase;
+ bool is_marco;
};
/* SIRFSOC_GPIO_PAD_EN set */
@@ -1088,12 +1090,21 @@ static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, unsigned selector
for (i = 0; i < mux->muxmask_counts; i++) {
u32 muxval;
- muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
- if (enable)
- muxval = muxval & ~mask[i].mask;
- else
- muxval = muxval | mask[i].mask;
- writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
+ if (!spmx->is_marco) {
+ muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
+ if (enable)
+ muxval = muxval & ~mask[i].mask;
+ else
+ muxval = muxval | mask[i].mask;
+ writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
+ } else {
+ if (enable)
+ writel(mask[i].mask, spmx->gpio_virtbase +
+ SIRFSOC_GPIO_PAD_EN_CLR(mask[i].group));
+ else
+ writel(mask[i].mask, spmx->gpio_virtbase +
+ SIRFSOC_GPIO_PAD_EN(mask[i].group));
+ }
}
if (mux->funcmask && enable) {
@@ -1158,9 +1169,14 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
spmx = pinctrl_dev_get_drvdata(pmxdev);
- muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
- muxval = muxval | (1 << (offset - range->pin_base));
- writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
+ if (!spmx->is_marco) {
+ muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
+ muxval = muxval | (1 << (offset - range->pin_base));
+ writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
+ } else {
+ writel(1 << (offset - range->pin_base), spmx->gpio_virtbase +
+ SIRFSOC_GPIO_PAD_EN(group));
+ }
return 0;
}
@@ -1218,6 +1234,7 @@ static void __iomem *sirfsoc_rsc_of_iomap(void)
{
const struct of_device_id rsc_ids[] = {
{ .compatible = "sirf,prima2-rsc" },
+ { .compatible = "sirf,marco-rsc" },
{}
};
struct device_node *np;
@@ -1259,6 +1276,9 @@ static int __devinit sirfsoc_pinmux_probe(struct platform_device *pdev)
goto out_no_rsc_remap;
}
+ if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
+ spmx->is_marco = 1;
+
/* Now register the pin controller and all pins it handles */
spmx->pmx = pinctrl_register(&sirfsoc_pinmux_desc, &pdev->dev, spmx);
if (!spmx->pmx) {
@@ -1287,6 +1307,7 @@ out_no_gpio_remap:
static const struct of_device_id pinmux_ids[] __devinitconst = {
{ .compatible = "sirf,prima2-pinctrl" },
+ { .compatible = "sirf,marco-pinctrl" },
{}
};
@@ -1621,8 +1642,8 @@ static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset,
spin_unlock_irqrestore(&bank->lock, flags);
}
-int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hwirq)
+static int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
{
struct sirfsoc_gpio_bank *bank = d->host_data;
@@ -1648,6 +1669,7 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
struct sirfsoc_gpio_bank *bank;
void *regs;
struct platform_device *pdev;
+ bool is_marco = false;
pdev = of_find_device_by_node(np);
if (!pdev)
@@ -1657,6 +1679,9 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
if (!regs)
return -ENOMEM;
+ if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
+ is_marco = 1;
+
for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
bank = &sgpio_bank[i];
spin_lock_init(&bank->lock);
@@ -1673,6 +1698,7 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
bank->chip.gc.of_node = np;
bank->chip.regs = regs;
bank->id = i;
+ bank->is_marco = is_marco;
bank->parent_irq = platform_get_irq(pdev, i);
if (bank->parent_irq < 0) {
err = bank->parent_irq;
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
index 7da0b371fd65..e9f80a54b3d0 100644
--- a/drivers/pinctrl/pinctrl-tegra.c
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -178,8 +178,9 @@ static int add_config(struct device *dev, unsigned long **configs,
return 0;
}
-void tegra_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
- struct pinctrl_map *map, unsigned num_maps)
+static void tegra_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map,
+ unsigned num_maps)
{
int i;
@@ -209,11 +210,11 @@ static const struct cfg_param {
{"nvidia,slew-rate-rising", TEGRA_PINCONF_PARAM_SLEW_RATE_RISING},
};
-int tegra_pinctrl_dt_subnode_to_map(struct device *dev,
- struct device_node *np,
- struct pinctrl_map **map,
- unsigned *reserved_maps,
- unsigned *num_maps)
+static int tegra_pinctrl_dt_subnode_to_map(struct device *dev,
+ struct device_node *np,
+ struct pinctrl_map **map,
+ unsigned *reserved_maps,
+ unsigned *num_maps)
{
int ret, i;
const char *function;
@@ -288,9 +289,10 @@ exit:
return ret;
}
-int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
- struct device_node *np_config,
- struct pinctrl_map **map, unsigned *num_maps)
+static int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map,
+ unsigned *num_maps)
{
unsigned reserved_maps;
struct device_node *np;
@@ -660,7 +662,7 @@ static void tegra_pinconf_config_dbg_show(struct pinctrl_dev *pctldev,
}
#endif
-struct pinconf_ops tegra_pinconf_ops = {
+static struct pinconf_ops tegra_pinconf_ops = {
.pin_config_get = tegra_pinconf_get,
.pin_config_set = tegra_pinconf_set,
.pin_config_group_get = tegra_pinconf_group_get,
diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c
index 309f5b9a70ec..b84de03ed54d 100644
--- a/drivers/pinctrl/pinctrl-u300.c
+++ b/drivers/pinctrl/pinctrl-u300.c
@@ -663,8 +663,6 @@ static const struct pinctrl_pin_desc u300_pads[] = {
struct u300_pmx {
struct device *dev;
struct pinctrl_dev *pctl;
- u32 phybase;
- u32 physize;
void __iomem *virtbase;
};
@@ -1013,52 +1011,11 @@ static struct pinmux_ops u300_pmx_ops = {
.disable = u300_pmx_disable,
};
-/*
- * GPIO ranges handled by the application-side COH901XXX GPIO controller
- * Very many pins can be converted into GPIO pins, but we only list those
- * that are useful in practice to cut down on tables.
- */
-#define U300_GPIO_RANGE(a, b, c) { .name = "COH901XXX", .id = a, .base= a, \
- .pin_base = b, .npins = c }
-
-static struct pinctrl_gpio_range u300_gpio_ranges[] = {
- U300_GPIO_RANGE(10, 426, 1),
- U300_GPIO_RANGE(11, 180, 1),
- U300_GPIO_RANGE(12, 165, 1), /* MS/MMC card insertion */
- U300_GPIO_RANGE(13, 179, 1),
- U300_GPIO_RANGE(14, 178, 1),
- U300_GPIO_RANGE(16, 194, 1),
- U300_GPIO_RANGE(17, 193, 1),
- U300_GPIO_RANGE(18, 192, 1),
- U300_GPIO_RANGE(19, 191, 1),
- U300_GPIO_RANGE(20, 186, 1),
- U300_GPIO_RANGE(21, 185, 1),
- U300_GPIO_RANGE(22, 184, 1),
- U300_GPIO_RANGE(23, 183, 1),
- U300_GPIO_RANGE(24, 182, 1),
- U300_GPIO_RANGE(25, 181, 1),
-};
-
-static struct pinctrl_gpio_range *u300_match_gpio_range(unsigned pin)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++) {
- struct pinctrl_gpio_range *range;
-
- range = &u300_gpio_ranges[i];
- if (pin >= range->pin_base &&
- pin <= (range->pin_base + range->npins - 1))
- return range;
- }
- return NULL;
-}
-
-int u300_pin_config_get(struct pinctrl_dev *pctldev,
- unsigned pin,
- unsigned long *config)
+static int u300_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *config)
{
- struct pinctrl_gpio_range *range = u300_match_gpio_range(pin);
+ struct pinctrl_gpio_range *range =
+ pinctrl_find_gpio_range_from_pin(pctldev, pin);
/* We get config for those pins we CAN get it for and that's it */
if (!range)
@@ -1069,11 +1026,11 @@ int u300_pin_config_get(struct pinctrl_dev *pctldev,
config);
}
-int u300_pin_config_set(struct pinctrl_dev *pctldev,
- unsigned pin,
- unsigned long config)
+static int u300_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long config)
{
- struct pinctrl_gpio_range *range = u300_match_gpio_range(pin);
+ struct pinctrl_gpio_range *range =
+ pinctrl_find_gpio_range_from_pin(pctldev, pin);
int ret;
if (!range)
@@ -1109,9 +1066,6 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev)
{
struct u300_pmx *upmx;
struct resource *res;
- struct gpio_chip *gpio_chip = dev_get_platdata(&pdev->dev);
- int ret;
- int i;
/* Create state holders etc for this driver */
upmx = devm_kzalloc(&pdev->dev, sizeof(*upmx), GFP_KERNEL);
@@ -1123,32 +1077,15 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENOENT;
- upmx->phybase = res->start;
- upmx->physize = resource_size(res);
-
- if (request_mem_region(upmx->phybase, upmx->physize,
- DRIVER_NAME) == NULL) {
- ret = -ENOMEM;
- goto out_no_memregion;
- }
- upmx->virtbase = ioremap(upmx->phybase, upmx->physize);
- if (!upmx->virtbase) {
- ret = -ENOMEM;
- goto out_no_remap;
- }
+ upmx->virtbase = devm_request_and_ioremap(&pdev->dev, res);
+ if (!upmx->virtbase)
+ return -ENOMEM;
upmx->pctl = pinctrl_register(&u300_pmx_desc, &pdev->dev, upmx);
if (!upmx->pctl) {
dev_err(&pdev->dev, "could not register U300 pinmux driver\n");
- ret = -EINVAL;
- goto out_no_pmx;
- }
-
- /* We will handle a range of GPIO pins */
- for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++) {
- u300_gpio_ranges[i].gc = gpio_chip;
- pinctrl_add_gpio_range(upmx->pctl, &u300_gpio_ranges[i]);
+ return -EINVAL;
}
platform_set_drvdata(pdev, upmx);
@@ -1156,14 +1093,6 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "initialized U300 pin control driver\n");
return 0;
-
-out_no_pmx:
- iounmap(upmx->virtbase);
-out_no_remap:
- platform_set_drvdata(pdev, NULL);
-out_no_memregion:
- release_mem_region(upmx->phybase, upmx->physize);
- return ret;
}
static int __devexit u300_pmx_remove(struct platform_device *pdev)
@@ -1171,8 +1100,6 @@ static int __devexit u300_pmx_remove(struct platform_device *pdev)
struct u300_pmx *upmx = platform_get_drvdata(pdev);
pinctrl_unregister(upmx->pctl);
- iounmap(upmx->virtbase);
- release_mem_region(upmx->phybase, upmx->physize);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c
index b9bcaec66223..ad90984ec500 100644
--- a/drivers/pinctrl/pinctrl-xway.c
+++ b/drivers/pinctrl/pinctrl-xway.c
@@ -522,7 +522,7 @@ static int xway_pinconf_set(struct pinctrl_dev *pctldev,
return 0;
}
-struct pinconf_ops xway_pinconf_ops = {
+static struct pinconf_ops xway_pinconf_ops = {
.pin_config_get = xway_pinconf_get,
.pin_config_set = xway_pinconf_set,
};
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index 9301a7a95eff..1a00658b3ea0 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -314,14 +314,11 @@ int pinmux_map_to_setting(struct pinctrl_map const *map,
{
struct pinctrl_dev *pctldev = setting->pctldev;
const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
- const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
char const * const *groups;
unsigned num_groups;
int ret;
const char *group;
int i;
- const unsigned *pins;
- unsigned num_pins;
if (!pmxops) {
dev_err(pctldev->dev, "does not support mux function\n");
@@ -376,53 +373,12 @@ int pinmux_map_to_setting(struct pinctrl_map const *map,
}
setting->data.mux.group = ret;
- ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, &pins,
- &num_pins);
- if (ret) {
- dev_err(pctldev->dev,
- "could not get pins for device %s group selector %d\n",
- pinctrl_dev_get_name(pctldev), setting->data.mux.group);
- return -ENODEV;
- }
-
- /* Try to allocate all pins in this group, one by one */
- for (i = 0; i < num_pins; i++) {
- ret = pin_request(pctldev, pins[i], map->dev_name, NULL);
- if (ret) {
- dev_err(pctldev->dev,
- "could not request pin %d on device %s\n",
- pins[i], pinctrl_dev_get_name(pctldev));
- /* On error release all taken pins */
- i--; /* this pin just failed */
- for (; i >= 0; i--)
- pin_free(pctldev, pins[i], NULL);
- return -ENODEV;
- }
- }
-
return 0;
}
void pinmux_free_setting(struct pinctrl_setting const *setting)
{
- struct pinctrl_dev *pctldev = setting->pctldev;
- const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
- const unsigned *pins;
- unsigned num_pins;
- int ret;
- int i;
-
- ret = pctlops->get_group_pins(pctldev, setting->data.mux.group,
- &pins, &num_pins);
- if (ret) {
- dev_err(pctldev->dev,
- "could not get pins for device %s group selector %d\n",
- pinctrl_dev_get_name(pctldev), setting->data.mux.group);
- return;
- }
-
- for (i = 0; i < num_pins; i++)
- pin_free(pctldev, pins[i], NULL);
+ /* This function is currently unused */
}
int pinmux_enable_setting(struct pinctrl_setting const *setting)
@@ -446,6 +402,18 @@ int pinmux_enable_setting(struct pinctrl_setting const *setting)
num_pins = 0;
}
+ /* Try to allocate all pins in this group, one by one */
+ for (i = 0; i < num_pins; i++) {
+ ret = pin_request(pctldev, pins[i], setting->dev_name, NULL);
+ if (ret) {
+ dev_err(pctldev->dev,
+ "could not request pin %d on device %s\n",
+ pins[i], pinctrl_dev_get_name(pctldev));
+ goto err_pin_request;
+ }
+ }
+
+ /* Now that we have acquired the pins, encode the mux setting */
for (i = 0; i < num_pins; i++) {
desc = pin_desc_get(pctldev, pins[i]);
if (desc == NULL) {
@@ -457,8 +425,26 @@ int pinmux_enable_setting(struct pinctrl_setting const *setting)
desc->mux_setting = &(setting->data.mux);
}
- return ops->enable(pctldev, setting->data.mux.func,
- setting->data.mux.group);
+ ret = ops->enable(pctldev, setting->data.mux.func,
+ setting->data.mux.group);
+
+ if (ret)
+ goto err_enable;
+
+ return 0;
+
+err_enable:
+ for (i = 0; i < num_pins; i++) {
+ desc = pin_desc_get(pctldev, pins[i]);
+ if (desc)
+ desc->mux_setting = NULL;
+ }
+err_pin_request:
+ /* On error release all taken pins */
+ while (--i >= 0)
+ pin_free(pctldev, pins[i], NULL);
+
+ return ret;
}
void pinmux_disable_setting(struct pinctrl_setting const *setting)
@@ -482,6 +468,7 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting)
num_pins = 0;
}
+ /* Flag the descs that no setting is active */
for (i = 0; i < num_pins; i++) {
desc = pin_desc_get(pctldev, pins[i]);
if (desc == NULL) {
@@ -493,6 +480,10 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting)
desc->mux_setting = NULL;
}
+ /* And release the pins */
+ for (i = 0; i < num_pins; i++)
+ pin_free(pctldev, pins[i], NULL);
+
if (ops->disable)
ops->disable(pctldev, setting->data.mux.func, setting->data.mux.group);
}
diff --git a/drivers/pinctrl/spear/Kconfig b/drivers/pinctrl/spear/Kconfig
index 91558791e766..04d93e602674 100644
--- a/drivers/pinctrl/spear/Kconfig
+++ b/drivers/pinctrl/spear/Kconfig
@@ -25,20 +25,31 @@ config PINCTRL_SPEAR310
bool "ST Microelectronics SPEAr310 SoC pin controller driver"
depends on MACH_SPEAR310
select PINCTRL_SPEAR3XX
+ select PINCTRL_SPEAR_PLGPIO
config PINCTRL_SPEAR320
bool "ST Microelectronics SPEAr320 SoC pin controller driver"
depends on MACH_SPEAR320
select PINCTRL_SPEAR3XX
+ select PINCTRL_SPEAR_PLGPIO
config PINCTRL_SPEAR1310
bool "ST Microelectronics SPEAr1310 SoC pin controller driver"
depends on MACH_SPEAR1310
select PINCTRL_SPEAR
+ select PINCTRL_SPEAR_PLGPIO
config PINCTRL_SPEAR1340
bool "ST Microelectronics SPEAr1340 SoC pin controller driver"
depends on MACH_SPEAR1340
select PINCTRL_SPEAR
+ select PINCTRL_SPEAR_PLGPIO
+
+config PINCTRL_SPEAR_PLGPIO
+ bool "SPEAr SoC PLGPIO Controller"
+ depends on GPIOLIB && PINCTRL_SPEAR
+ help
+ Say yes here to support PLGPIO controller on ST Microelectronics SPEAr
+ SoCs.
endif
diff --git a/drivers/pinctrl/spear/Makefile b/drivers/pinctrl/spear/Makefile
index b28a7ba22443..0e400ebeb8ff 100644
--- a/drivers/pinctrl/spear/Makefile
+++ b/drivers/pinctrl/spear/Makefile
@@ -1,5 +1,6 @@
# SPEAr pinmux support
+obj-$(CONFIG_PINCTRL_SPEAR_PLGPIO) += pinctrl-plgpio.o
obj-$(CONFIG_PINCTRL_SPEAR) += pinctrl-spear.o
obj-$(CONFIG_PINCTRL_SPEAR3XX) += pinctrl-spear3xx.o
obj-$(CONFIG_PINCTRL_SPEAR300) += pinctrl-spear300.o
diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c
new file mode 100644
index 000000000000..4c045053bbdd
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-plgpio.c
@@ -0,0 +1,758 @@
+/*
+ * SPEAr platform PLGPIO driver
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/spinlock.h>
+#include <asm/mach/irq.h>
+
+#define MAX_GPIO_PER_REG 32
+#define PIN_OFFSET(pin) (pin % MAX_GPIO_PER_REG)
+#define REG_OFFSET(base, reg, pin) (base + reg + (pin / MAX_GPIO_PER_REG) \
+ * sizeof(int *))
+
+/*
+ * plgpio pins in all machines are not one to one mapped, bitwise with registers
+ * bits. These set of macros define register masks for which below functions
+ * (pin_to_offset and offset_to_pin) are required to be called.
+ */
+#define PTO_ENB_REG 0x001
+#define PTO_WDATA_REG 0x002
+#define PTO_DIR_REG 0x004
+#define PTO_IE_REG 0x008
+#define PTO_RDATA_REG 0x010
+#define PTO_MIS_REG 0x020
+
+struct plgpio_regs {
+ u32 enb; /* enable register */
+ u32 wdata; /* write data register */
+ u32 dir; /* direction set register */
+ u32 rdata; /* read data register */
+ u32 ie; /* interrupt enable register */
+ u32 mis; /* mask interrupt status register */
+ u32 eit; /* edge interrupt type */
+};
+
+/*
+ * struct plgpio: plgpio driver specific structure
+ *
+ * lock: lock for guarding gpio registers
+ * base: base address of plgpio block
+ * irq_base: irq number of plgpio0
+ * chip: gpio framework specific chip information structure
+ * p2o: function ptr for pin to offset conversion. This is required only for
+ * machines where mapping b/w pin and offset is not 1-to-1.
+ * o2p: function ptr for offset to pin conversion. This is required only for
+ * machines where mapping b/w pin and offset is not 1-to-1.
+ * p2o_regs: mask of registers for which p2o and o2p are applicable
+ * regs: register offsets
+ * csave_regs: context save registers for standby/sleep/hibernate cases
+ */
+struct plgpio {
+ spinlock_t lock;
+ void __iomem *base;
+ struct clk *clk;
+ unsigned irq_base;
+ struct irq_domain *irq_domain;
+ struct gpio_chip chip;
+ int (*p2o)(int pin); /* pin_to_offset */
+ int (*o2p)(int offset); /* offset_to_pin */
+ u32 p2o_regs;
+ struct plgpio_regs regs;
+#ifdef CONFIG_PM
+ struct plgpio_regs *csave_regs;
+#endif
+};
+
+/* register manipulation inline functions */
+static inline u32 is_plgpio_set(void __iomem *base, u32 pin, u32 reg)
+{
+ u32 offset = PIN_OFFSET(pin);
+ void __iomem *reg_off = REG_OFFSET(base, reg, pin);
+ u32 val = readl_relaxed(reg_off);
+
+ return !!(val & (1 << offset));
+}
+
+static inline void plgpio_reg_set(void __iomem *base, u32 pin, u32 reg)
+{
+ u32 offset = PIN_OFFSET(pin);
+ void __iomem *reg_off = REG_OFFSET(base, reg, pin);
+ u32 val = readl_relaxed(reg_off);
+
+ writel_relaxed(val | (1 << offset), reg_off);
+}
+
+static inline void plgpio_reg_reset(void __iomem *base, u32 pin, u32 reg)
+{
+ u32 offset = PIN_OFFSET(pin);
+ void __iomem *reg_off = REG_OFFSET(base, reg, pin);
+ u32 val = readl_relaxed(reg_off);
+
+ writel_relaxed(val & ~(1 << offset), reg_off);
+}
+
+/* gpio framework specific routines */
+static int plgpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+ unsigned long flags;
+
+ /* get correct offset for "offset" pin */
+ if (plgpio->p2o && (plgpio->p2o_regs & PTO_DIR_REG)) {
+ offset = plgpio->p2o(offset);
+ if (offset == -1)
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&plgpio->lock, flags);
+ plgpio_reg_set(plgpio->base, offset, plgpio->regs.dir);
+ spin_unlock_irqrestore(&plgpio->lock, flags);
+
+ return 0;
+}
+
+static int plgpio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+ unsigned long flags;
+ unsigned dir_offset = offset, wdata_offset = offset, tmp;
+
+ /* get correct offset for "offset" pin */
+ if (plgpio->p2o && (plgpio->p2o_regs & (PTO_DIR_REG | PTO_WDATA_REG))) {
+ tmp = plgpio->p2o(offset);
+ if (tmp == -1)
+ return -EINVAL;
+
+ if (plgpio->p2o_regs & PTO_DIR_REG)
+ dir_offset = tmp;
+ if (plgpio->p2o_regs & PTO_WDATA_REG)
+ wdata_offset = tmp;
+ }
+
+ spin_lock_irqsave(&plgpio->lock, flags);
+ if (value)
+ plgpio_reg_set(plgpio->base, wdata_offset,
+ plgpio->regs.wdata);
+ else
+ plgpio_reg_reset(plgpio->base, wdata_offset,
+ plgpio->regs.wdata);
+
+ plgpio_reg_reset(plgpio->base, dir_offset, plgpio->regs.dir);
+ spin_unlock_irqrestore(&plgpio->lock, flags);
+
+ return 0;
+}
+
+static int plgpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+ struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+
+ if (offset >= chip->ngpio)
+ return -EINVAL;
+
+ /* get correct offset for "offset" pin */
+ if (plgpio->p2o && (plgpio->p2o_regs & PTO_RDATA_REG)) {
+ offset = plgpio->p2o(offset);
+ if (offset == -1)
+ return -EINVAL;
+ }
+
+ return is_plgpio_set(plgpio->base, offset, plgpio->regs.rdata);
+}
+
+static void plgpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+
+ if (offset >= chip->ngpio)
+ return;
+
+ /* get correct offset for "offset" pin */
+ if (plgpio->p2o && (plgpio->p2o_regs & PTO_WDATA_REG)) {
+ offset = plgpio->p2o(offset);
+ if (offset == -1)
+ return;
+ }
+
+ if (value)
+ plgpio_reg_set(plgpio->base, offset, plgpio->regs.wdata);
+ else
+ plgpio_reg_reset(plgpio->base, offset, plgpio->regs.wdata);
+}
+
+static int plgpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+ int gpio = chip->base + offset;
+ unsigned long flags;
+ int ret = 0;
+
+ if (offset >= chip->ngpio)
+ return -EINVAL;
+
+ ret = pinctrl_request_gpio(gpio);
+ if (ret)
+ return ret;
+
+ if (!IS_ERR(plgpio->clk)) {
+ ret = clk_enable(plgpio->clk);
+ if (ret)
+ goto err0;
+ }
+
+ if (plgpio->regs.enb == -1)
+ return 0;
+
+ /*
+ * put gpio in IN mode before enabling it. This make enabling gpio safe
+ */
+ ret = plgpio_direction_input(chip, offset);
+ if (ret)
+ goto err1;
+
+ /* get correct offset for "offset" pin */
+ if (plgpio->p2o && (plgpio->p2o_regs & PTO_ENB_REG)) {
+ offset = plgpio->p2o(offset);
+ if (offset == -1) {
+ ret = -EINVAL;
+ goto err1;
+ }
+ }
+
+ spin_lock_irqsave(&plgpio->lock, flags);
+ plgpio_reg_set(plgpio->base, offset, plgpio->regs.enb);
+ spin_unlock_irqrestore(&plgpio->lock, flags);
+ return 0;
+
+err1:
+ if (!IS_ERR(plgpio->clk))
+ clk_disable(plgpio->clk);
+err0:
+ pinctrl_free_gpio(gpio);
+ return ret;
+}
+
+static void plgpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+ int gpio = chip->base + offset;
+ unsigned long flags;
+
+ if (offset >= chip->ngpio)
+ return;
+
+ if (plgpio->regs.enb == -1)
+ goto disable_clk;
+
+ /* get correct offset for "offset" pin */
+ if (plgpio->p2o && (plgpio->p2o_regs & PTO_ENB_REG)) {
+ offset = plgpio->p2o(offset);
+ if (offset == -1)
+ return;
+ }
+
+ spin_lock_irqsave(&plgpio->lock, flags);
+ plgpio_reg_reset(plgpio->base, offset, plgpio->regs.enb);
+ spin_unlock_irqrestore(&plgpio->lock, flags);
+
+disable_clk:
+ if (!IS_ERR(plgpio->clk))
+ clk_disable(plgpio->clk);
+
+ pinctrl_free_gpio(gpio);
+}
+
+static int plgpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+
+ if (IS_ERR_VALUE(plgpio->irq_base))
+ return -EINVAL;
+
+ return irq_find_mapping(plgpio->irq_domain, offset);
+}
+
+/* PLGPIO IRQ */
+static void plgpio_irq_disable(struct irq_data *d)
+{
+ struct plgpio *plgpio = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - plgpio->irq_base;
+ unsigned long flags;
+
+ /* get correct offset for "offset" pin */
+ if (plgpio->p2o && (plgpio->p2o_regs & PTO_IE_REG)) {
+ offset = plgpio->p2o(offset);
+ if (offset == -1)
+ return;
+ }
+
+ spin_lock_irqsave(&plgpio->lock, flags);
+ plgpio_reg_set(plgpio->base, offset, plgpio->regs.ie);
+ spin_unlock_irqrestore(&plgpio->lock, flags);
+}
+
+static void plgpio_irq_enable(struct irq_data *d)
+{
+ struct plgpio *plgpio = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - plgpio->irq_base;
+ unsigned long flags;
+
+ /* get correct offset for "offset" pin */
+ if (plgpio->p2o && (plgpio->p2o_regs & PTO_IE_REG)) {
+ offset = plgpio->p2o(offset);
+ if (offset == -1)
+ return;
+ }
+
+ spin_lock_irqsave(&plgpio->lock, flags);
+ plgpio_reg_reset(plgpio->base, offset, plgpio->regs.ie);
+ spin_unlock_irqrestore(&plgpio->lock, flags);
+}
+
+static int plgpio_irq_set_type(struct irq_data *d, unsigned trigger)
+{
+ struct plgpio *plgpio = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - plgpio->irq_base;
+ void __iomem *reg_off;
+ unsigned int supported_type = 0, val;
+
+ if (offset >= plgpio->chip.ngpio)
+ return -EINVAL;
+
+ if (plgpio->regs.eit == -1)
+ supported_type = IRQ_TYPE_LEVEL_HIGH;
+ else
+ supported_type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+
+ if (!(trigger & supported_type))
+ return -EINVAL;
+
+ if (plgpio->regs.eit == -1)
+ return 0;
+
+ reg_off = REG_OFFSET(plgpio->base, plgpio->regs.eit, offset);
+ val = readl_relaxed(reg_off);
+
+ offset = PIN_OFFSET(offset);
+ if (trigger & IRQ_TYPE_EDGE_RISING)
+ writel_relaxed(val | (1 << offset), reg_off);
+ else
+ writel_relaxed(val & ~(1 << offset), reg_off);
+
+ return 0;
+}
+
+static struct irq_chip plgpio_irqchip = {
+ .name = "PLGPIO",
+ .irq_enable = plgpio_irq_enable,
+ .irq_disable = plgpio_irq_disable,
+ .irq_set_type = plgpio_irq_set_type,
+};
+
+static void plgpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+ struct plgpio *plgpio = irq_get_handler_data(irq);
+ struct irq_chip *irqchip = irq_desc_get_chip(desc);
+ int regs_count, count, pin, offset, i = 0;
+ unsigned long pending;
+
+ count = plgpio->chip.ngpio;
+ regs_count = DIV_ROUND_UP(count, MAX_GPIO_PER_REG);
+
+ chained_irq_enter(irqchip, desc);
+ /* check all plgpio MIS registers for a possible interrupt */
+ for (; i < regs_count; i++) {
+ pending = readl_relaxed(plgpio->base + plgpio->regs.mis +
+ i * sizeof(int *));
+ if (!pending)
+ continue;
+
+ /* clear interrupts */
+ writel_relaxed(~pending, plgpio->base + plgpio->regs.mis +
+ i * sizeof(int *));
+ /*
+ * clear extra bits in last register having gpios < MAX/REG
+ * ex: Suppose there are max 102 plgpios. then last register
+ * must have only (102 - MAX_GPIO_PER_REG * 3) = 6 relevant bits
+ * so, we must not take other 28 bits into consideration for
+ * checking interrupt. so clear those bits.
+ */
+ count = count - i * MAX_GPIO_PER_REG;
+ if (count < MAX_GPIO_PER_REG)
+ pending &= (1 << count) - 1;
+
+ for_each_set_bit(offset, &pending, MAX_GPIO_PER_REG) {
+ /* get correct pin for "offset" */
+ if (plgpio->o2p && (plgpio->p2o_regs & PTO_MIS_REG)) {
+ pin = plgpio->o2p(offset);
+ if (pin == -1)
+ continue;
+ } else
+ pin = offset;
+
+ /* get correct irq line number */
+ pin = i * MAX_GPIO_PER_REG + pin;
+ generic_handle_irq(plgpio_to_irq(&plgpio->chip, pin));
+ }
+ }
+ chained_irq_exit(irqchip, desc);
+}
+
+/*
+ * pin to offset and offset to pin converter functions
+ *
+ * In spear310 there is inconsistency among bit positions in plgpio regiseters,
+ * for different plgpio pins. For example: for pin 27, bit offset is 23, pin
+ * 28-33 are not supported, pin 95 has offset bit 95, bit 100 has offset bit 1
+ */
+static int spear310_p2o(int pin)
+{
+ int offset = pin;
+
+ if (pin <= 27)
+ offset += 4;
+ else if (pin <= 33)
+ offset = -1;
+ else if (pin <= 97)
+ offset -= 2;
+ else if (pin <= 101)
+ offset = 101 - pin;
+ else
+ offset = -1;
+
+ return offset;
+}
+
+int spear310_o2p(int offset)
+{
+ if (offset <= 3)
+ return 101 - offset;
+ else if (offset <= 31)
+ return offset - 4;
+ else
+ return offset + 2;
+}
+
+static int __devinit plgpio_probe_dt(struct platform_device *pdev,
+ struct plgpio *plgpio)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int ret = -EINVAL;
+ u32 val;
+
+ if (of_machine_is_compatible("st,spear310")) {
+ plgpio->p2o = spear310_p2o;
+ plgpio->o2p = spear310_o2p;
+ plgpio->p2o_regs = PTO_WDATA_REG | PTO_DIR_REG | PTO_IE_REG |
+ PTO_RDATA_REG | PTO_MIS_REG;
+ }
+
+ if (!of_property_read_u32(np, "st-plgpio,ngpio", &val)) {
+ plgpio->chip.ngpio = val;
+ } else {
+ dev_err(&pdev->dev, "DT: Invalid ngpio field\n");
+ goto end;
+ }
+
+ if (!of_property_read_u32(np, "st-plgpio,enb-reg", &val))
+ plgpio->regs.enb = val;
+ else
+ plgpio->regs.enb = -1;
+
+ if (!of_property_read_u32(np, "st-plgpio,wdata-reg", &val)) {
+ plgpio->regs.wdata = val;
+ } else {
+ dev_err(&pdev->dev, "DT: Invalid wdata reg\n");
+ goto end;
+ }
+
+ if (!of_property_read_u32(np, "st-plgpio,dir-reg", &val)) {
+ plgpio->regs.dir = val;
+ } else {
+ dev_err(&pdev->dev, "DT: Invalid dir reg\n");
+ goto end;
+ }
+
+ if (!of_property_read_u32(np, "st-plgpio,ie-reg", &val)) {
+ plgpio->regs.ie = val;
+ } else {
+ dev_err(&pdev->dev, "DT: Invalid ie reg\n");
+ goto end;
+ }
+
+ if (!of_property_read_u32(np, "st-plgpio,rdata-reg", &val)) {
+ plgpio->regs.rdata = val;
+ } else {
+ dev_err(&pdev->dev, "DT: Invalid rdata reg\n");
+ goto end;
+ }
+
+ if (!of_property_read_u32(np, "st-plgpio,mis-reg", &val)) {
+ plgpio->regs.mis = val;
+ } else {
+ dev_err(&pdev->dev, "DT: Invalid mis reg\n");
+ goto end;
+ }
+
+ if (!of_property_read_u32(np, "st-plgpio,eit-reg", &val))
+ plgpio->regs.eit = val;
+ else
+ plgpio->regs.eit = -1;
+
+ return 0;
+
+end:
+ return ret;
+}
+static int __devinit plgpio_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct plgpio *plgpio;
+ struct resource *res;
+ int ret, irq, i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "invalid IORESOURCE_MEM\n");
+ return -EBUSY;
+ }
+
+ plgpio = devm_kzalloc(&pdev->dev, sizeof(*plgpio), GFP_KERNEL);
+ if (!plgpio) {
+ dev_err(&pdev->dev, "memory allocation fail\n");
+ return -ENOMEM;
+ }
+
+ plgpio->base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!plgpio->base) {
+ dev_err(&pdev->dev, "request and ioremap fail\n");
+ return -ENOMEM;
+ }
+
+ ret = plgpio_probe_dt(pdev, plgpio);
+ if (ret) {
+ dev_err(&pdev->dev, "DT probe failed\n");
+ return ret;
+ }
+
+ plgpio->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(plgpio->clk))
+ dev_warn(&pdev->dev, "clk_get() failed, work without it\n");
+
+#ifdef CONFIG_PM
+ plgpio->csave_regs = devm_kzalloc(&pdev->dev,
+ sizeof(*plgpio->csave_regs) *
+ DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG),
+ GFP_KERNEL);
+ if (!plgpio->csave_regs) {
+ dev_err(&pdev->dev, "csave registers memory allocation fail\n");
+ return -ENOMEM;
+ }
+#endif
+
+ platform_set_drvdata(pdev, plgpio);
+ spin_lock_init(&plgpio->lock);
+
+ plgpio->irq_base = -1;
+ plgpio->chip.base = -1;
+ plgpio->chip.request = plgpio_request;
+ plgpio->chip.free = plgpio_free;
+ plgpio->chip.direction_input = plgpio_direction_input;
+ plgpio->chip.direction_output = plgpio_direction_output;
+ plgpio->chip.get = plgpio_get_value;
+ plgpio->chip.set = plgpio_set_value;
+ plgpio->chip.to_irq = plgpio_to_irq;
+ plgpio->chip.label = dev_name(&pdev->dev);
+ plgpio->chip.dev = &pdev->dev;
+ plgpio->chip.owner = THIS_MODULE;
+
+ if (!IS_ERR(plgpio->clk)) {
+ ret = clk_prepare(plgpio->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "clk prepare failed\n");
+ return ret;
+ }
+ }
+
+ ret = gpiochip_add(&plgpio->chip);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to add gpio chip\n");
+ goto unprepare_clk;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_info(&pdev->dev, "irqs not supported\n");
+ return 0;
+ }
+
+ plgpio->irq_base = irq_alloc_descs(-1, 0, plgpio->chip.ngpio, 0);
+ if (IS_ERR_VALUE(plgpio->irq_base)) {
+ /* we would not support irq for gpio */
+ dev_warn(&pdev->dev, "couldn't allocate irq base\n");
+ return 0;
+ }
+
+ plgpio->irq_domain = irq_domain_add_legacy(np, plgpio->chip.ngpio,
+ plgpio->irq_base, 0, &irq_domain_simple_ops, NULL);
+ if (WARN_ON(!plgpio->irq_domain)) {
+ dev_err(&pdev->dev, "irq domain init failed\n");
+ irq_free_descs(plgpio->irq_base, plgpio->chip.ngpio);
+ ret = -ENXIO;
+ goto remove_gpiochip;
+ }
+
+ irq_set_chained_handler(irq, plgpio_irq_handler);
+ for (i = 0; i < plgpio->chip.ngpio; i++) {
+ irq_set_chip_and_handler(i + plgpio->irq_base, &plgpio_irqchip,
+ handle_simple_irq);
+ set_irq_flags(i + plgpio->irq_base, IRQF_VALID);
+ irq_set_chip_data(i + plgpio->irq_base, plgpio);
+ }
+
+ irq_set_handler_data(irq, plgpio);
+ dev_info(&pdev->dev, "PLGPIO registered with IRQs\n");
+
+ return 0;
+
+remove_gpiochip:
+ dev_info(&pdev->dev, "Remove gpiochip\n");
+ if (gpiochip_remove(&plgpio->chip))
+ dev_err(&pdev->dev, "unable to remove gpiochip\n");
+unprepare_clk:
+ if (!IS_ERR(plgpio->clk))
+ clk_unprepare(plgpio->clk);
+
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int plgpio_suspend(struct device *dev)
+{
+ struct plgpio *plgpio = dev_get_drvdata(dev);
+ int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG);
+ void __iomem *off;
+
+ for (i = 0; i < reg_count; i++) {
+ off = plgpio->base + i * sizeof(int *);
+
+ if (plgpio->regs.enb != -1)
+ plgpio->csave_regs[i].enb =
+ readl_relaxed(plgpio->regs.enb + off);
+ if (plgpio->regs.eit != -1)
+ plgpio->csave_regs[i].eit =
+ readl_relaxed(plgpio->regs.eit + off);
+ plgpio->csave_regs[i].wdata = readl_relaxed(plgpio->regs.wdata +
+ off);
+ plgpio->csave_regs[i].dir = readl_relaxed(plgpio->regs.dir +
+ off);
+ plgpio->csave_regs[i].ie = readl_relaxed(plgpio->regs.ie + off);
+ }
+
+ return 0;
+}
+
+/*
+ * This is used to correct the values in end registers. End registers contain
+ * extra bits that might be used for other purpose in platform. So, we shouldn't
+ * overwrite these bits. This macro, reads given register again, preserves other
+ * bit values (non-plgpio bits), and retain captured value (plgpio bits).
+ */
+#define plgpio_prepare_reg(__reg, _off, _mask, _tmp) \
+{ \
+ _tmp = readl_relaxed(plgpio->regs.__reg + _off); \
+ _tmp &= ~_mask; \
+ plgpio->csave_regs[i].__reg = \
+ _tmp | (plgpio->csave_regs[i].__reg & _mask); \
+}
+
+static int plgpio_resume(struct device *dev)
+{
+ struct plgpio *plgpio = dev_get_drvdata(dev);
+ int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG);
+ void __iomem *off;
+ u32 mask, tmp;
+
+ for (i = 0; i < reg_count; i++) {
+ off = plgpio->base + i * sizeof(int *);
+
+ if (i == reg_count - 1) {
+ mask = (1 << (plgpio->chip.ngpio - i *
+ MAX_GPIO_PER_REG)) - 1;
+
+ if (plgpio->regs.enb != -1)
+ plgpio_prepare_reg(enb, off, mask, tmp);
+
+ if (plgpio->regs.eit != -1)
+ plgpio_prepare_reg(eit, off, mask, tmp);
+
+ plgpio_prepare_reg(wdata, off, mask, tmp);
+ plgpio_prepare_reg(dir, off, mask, tmp);
+ plgpio_prepare_reg(ie, off, mask, tmp);
+ }
+
+ writel_relaxed(plgpio->csave_regs[i].wdata, plgpio->regs.wdata +
+ off);
+ writel_relaxed(plgpio->csave_regs[i].dir, plgpio->regs.dir +
+ off);
+
+ if (plgpio->regs.eit != -1)
+ writel_relaxed(plgpio->csave_regs[i].eit,
+ plgpio->regs.eit + off);
+
+ writel_relaxed(plgpio->csave_regs[i].ie, plgpio->regs.ie + off);
+
+ if (plgpio->regs.enb != -1)
+ writel_relaxed(plgpio->csave_regs[i].enb,
+ plgpio->regs.enb + off);
+ }
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(plgpio_dev_pm_ops, plgpio_suspend, plgpio_resume);
+
+static const struct of_device_id plgpio_of_match[] = {
+ { .compatible = "st,spear-plgpio" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, plgpio_of_match);
+
+static struct platform_driver plgpio_driver = {
+ .probe = plgpio_probe,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "spear-plgpio",
+ .pm = &plgpio_dev_pm_ops,
+ .of_match_table = of_match_ptr(plgpio_of_match),
+ },
+};
+
+static int __init plgpio_init(void)
+{
+ return platform_driver_register(&plgpio_driver);
+}
+subsys_initcall(plgpio_init);
+
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
+MODULE_DESCRIPTION("ST Microlectronics SPEAr PLGPIO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c
index b1fd6ee33c6c..bf78eb7f85c4 100644
--- a/drivers/pinctrl/spear/pinctrl-spear.c
+++ b/drivers/pinctrl/spear/pinctrl-spear.c
@@ -14,10 +14,10 @@
*/
#include <linux/err.h>
-#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_gpio.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
@@ -28,14 +28,26 @@
#define DRIVER_NAME "spear-pinmux"
-static inline u32 pmx_readl(struct spear_pmx *pmx, u32 reg)
+static void muxregs_endisable(struct spear_pmx *pmx,
+ struct spear_muxreg *muxregs, u8 count, bool enable)
{
- return readl_relaxed(pmx->vbase + reg);
-}
+ struct spear_muxreg *muxreg;
+ u32 val, temp, j;
-static inline void pmx_writel(struct spear_pmx *pmx, u32 val, u32 reg)
-{
- writel_relaxed(val, pmx->vbase + reg);
+ for (j = 0; j < count; j++) {
+ muxreg = &muxregs[j];
+
+ val = pmx_readl(pmx, muxreg->reg);
+ val &= ~muxreg->mask;
+
+ if (enable)
+ temp = muxreg->val;
+ else
+ temp = ~muxreg->val;
+
+ val |= muxreg->mask & temp;
+ pmx_writel(pmx, val, muxreg->reg);
+ }
}
static int set_mode(struct spear_pmx *pmx, int mode)
@@ -70,6 +82,17 @@ static int set_mode(struct spear_pmx *pmx, int mode)
return 0;
}
+void __devinit
+pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup,
+ unsigned count, u16 reg)
+{
+ int i, j;
+
+ for (i = 0; i < count; i++)
+ for (j = 0; j < gpio_pingroup[i].nmuxregs; j++)
+ gpio_pingroup[i].muxregs[j].reg = reg;
+}
+
void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg)
{
struct spear_pingroup *pgroup;
@@ -121,9 +144,10 @@ static void spear_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
seq_printf(s, " " DRIVER_NAME);
}
-int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
- struct device_node *np_config,
- struct pinctrl_map **map, unsigned *num_maps)
+static int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map,
+ unsigned *num_maps)
{
struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
struct device_node *np;
@@ -168,8 +192,9 @@ int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
return 0;
}
-void spear_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
- struct pinctrl_map *map, unsigned num_maps)
+static void spear_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map,
+ unsigned num_maps)
{
kfree(map);
}
@@ -216,9 +241,7 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev,
struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
const struct spear_pingroup *pgroup;
const struct spear_modemux *modemux;
- struct spear_muxreg *muxreg;
- u32 val, temp;
- int i, j;
+ int i;
bool found = false;
pgroup = pmx->machdata->groups[group];
@@ -233,20 +256,8 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev,
}
found = true;
- for (j = 0; j < modemux->nmuxregs; j++) {
- muxreg = &modemux->muxregs[j];
-
- val = pmx_readl(pmx, muxreg->reg);
- val &= ~muxreg->mask;
-
- if (enable)
- temp = muxreg->val;
- else
- temp = ~muxreg->val;
-
- val |= muxreg->mask & temp;
- pmx_writel(pmx, val, muxreg->reg);
- }
+ muxregs_endisable(pmx, modemux->muxregs, modemux->nmuxregs,
+ enable);
}
if (!found) {
@@ -270,12 +281,74 @@ static void spear_pinctrl_disable(struct pinctrl_dev *pctldev,
spear_pinctrl_endisable(pctldev, function, group, false);
}
+/* gpio with pinmux */
+static struct spear_gpio_pingroup *get_gpio_pingroup(struct spear_pmx *pmx,
+ unsigned pin)
+{
+ struct spear_gpio_pingroup *gpio_pingroup;
+ int i, j;
+
+ if (!pmx->machdata->gpio_pingroups)
+ return NULL;
+
+ for (i = 0; i < pmx->machdata->ngpio_pingroups; i++) {
+ gpio_pingroup = &pmx->machdata->gpio_pingroups[i];
+
+ for (j = 0; j < gpio_pingroup->npins; j++) {
+ if (gpio_pingroup->pins[j] == pin)
+ return gpio_pingroup;
+ }
+ }
+
+ return NULL;
+}
+
+static int gpio_request_endisable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned offset, bool enable)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+ struct spear_pinctrl_machdata *machdata = pmx->machdata;
+ struct spear_gpio_pingroup *gpio_pingroup;
+
+ /*
+ * Some SoC have configuration options applicable to group of pins,
+ * rather than a single pin.
+ */
+ gpio_pingroup = get_gpio_pingroup(pmx, offset);
+ if (gpio_pingroup)
+ muxregs_endisable(pmx, gpio_pingroup->muxregs,
+ gpio_pingroup->nmuxregs, enable);
+
+ /*
+ * SoC may need some extra configurations, or configurations for single
+ * pin
+ */
+ if (machdata->gpio_request_endisable)
+ machdata->gpio_request_endisable(pmx, offset, enable);
+
+ return 0;
+}
+
+static int gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned offset)
+{
+ return gpio_request_endisable(pctldev, range, offset, true);
+}
+
+static void gpio_disable_free(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned offset)
+{
+ gpio_request_endisable(pctldev, range, offset, false);
+}
+
static struct pinmux_ops spear_pinmux_ops = {
.get_functions_count = spear_pinctrl_get_funcs_count,
.get_function_name = spear_pinctrl_get_func_name,
.get_function_groups = spear_pinctrl_get_func_groups,
.enable = spear_pinctrl_enable,
.disable = spear_pinctrl_disable,
+ .gpio_request_enable = gpio_request_enable,
+ .gpio_disable_free = gpio_disable_free,
};
static struct pinctrl_desc spear_pinctrl_desc = {
diff --git a/drivers/pinctrl/spear/pinctrl-spear.h b/drivers/pinctrl/spear/pinctrl-spear.h
index d950eb78d939..b06332719b2c 100644
--- a/drivers/pinctrl/spear/pinctrl-spear.h
+++ b/drivers/pinctrl/spear/pinctrl-spear.h
@@ -12,11 +12,14 @@
#ifndef __PINMUX_SPEAR_H__
#define __PINMUX_SPEAR_H__
+#include <linux/gpio.h>
+#include <linux/io.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/types.h>
struct platform_device;
struct device;
+struct spear_pmx;
/**
* struct spear_pmx_mode - SPEAr pmx mode
@@ -46,6 +49,44 @@ struct spear_muxreg {
u32 val;
};
+struct spear_gpio_pingroup {
+ const unsigned *pins;
+ unsigned npins;
+ struct spear_muxreg *muxregs;
+ u8 nmuxregs;
+};
+
+/* ste: set to enable */
+#define DEFINE_MUXREG(__pins, __muxreg, __mask, __ste) \
+static struct spear_muxreg __pins##_muxregs[] = { \
+ { \
+ .reg = __muxreg, \
+ .mask = __mask, \
+ .val = __ste ? __mask : 0, \
+ }, \
+}
+
+#define DEFINE_2_MUXREG(__pins, __muxreg1, __muxreg2, __mask, __ste1, __ste2) \
+static struct spear_muxreg __pins##_muxregs[] = { \
+ { \
+ .reg = __muxreg1, \
+ .mask = __mask, \
+ .val = __ste1 ? __mask : 0, \
+ }, { \
+ .reg = __muxreg2, \
+ .mask = __mask, \
+ .val = __ste2 ? __mask : 0, \
+ }, \
+}
+
+#define GPIO_PINGROUP(__pins) \
+ { \
+ .pins = __pins, \
+ .npins = ARRAY_SIZE(__pins), \
+ .muxregs = __pins##_muxregs, \
+ .nmuxregs = ARRAY_SIZE(__pins##_muxregs), \
+ }
+
/**
* struct spear_modemux - SPEAr mode mux configuration
* @modes: mode ids supported by this group of muxregs
@@ -100,6 +141,8 @@ struct spear_function {
* @nfunctions: The numbmer of entries in @functions.
* @groups: An array describing all pin groups the pin SoC supports.
* @ngroups: The numbmer of entries in @groups.
+ * @gpio_pingroups: gpio pingroups
+ * @ngpio_pingroups: gpio pingroups count
*
* @modes_supported: Does SoC support modes
* @mode: mode configured from probe
@@ -113,6 +156,10 @@ struct spear_pinctrl_machdata {
unsigned nfunctions;
struct spear_pingroup **groups;
unsigned ngroups;
+ struct spear_gpio_pingroup *gpio_pingroups;
+ void (*gpio_request_endisable)(struct spear_pmx *pmx, int offset,
+ bool enable);
+ unsigned ngpio_pingroups;
bool modes_supported;
u16 mode;
@@ -135,7 +182,20 @@ struct spear_pmx {
};
/* exported routines */
+static inline u32 pmx_readl(struct spear_pmx *pmx, u32 reg)
+{
+ return readl_relaxed(pmx->vbase + reg);
+}
+
+static inline void pmx_writel(struct spear_pmx *pmx, u32 val, u32 reg)
+{
+ writel_relaxed(val, pmx->vbase + reg);
+}
+
void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg);
+void __devinit
+pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup,
+ unsigned count, u16 reg);
int __devinit spear_pinctrl_probe(struct platform_device *pdev,
struct spear_pinctrl_machdata *machdata);
int __devexit spear_pinctrl_remove(struct platform_device *pdev);
diff --git a/drivers/pinctrl/spear/pinctrl-spear1310.c b/drivers/pinctrl/spear/pinctrl-spear1310.c
index 0436fc7895d6..30134f727455 100644
--- a/drivers/pinctrl/spear/pinctrl-spear1310.c
+++ b/drivers/pinctrl/spear/pinctrl-spear1310.c
@@ -2418,6 +2418,268 @@ static struct spear_function *spear1310_functions[] = {
&gpt64_function,
};
+static const unsigned pin18[] = { 18, };
+static const unsigned pin19[] = { 19, };
+static const unsigned pin20[] = { 20, };
+static const unsigned pin21[] = { 21, };
+static const unsigned pin22[] = { 22, };
+static const unsigned pin23[] = { 23, };
+static const unsigned pin54[] = { 54, };
+static const unsigned pin55[] = { 55, };
+static const unsigned pin56[] = { 56, };
+static const unsigned pin57[] = { 57, };
+static const unsigned pin58[] = { 58, };
+static const unsigned pin59[] = { 59, };
+static const unsigned pin60[] = { 60, };
+static const unsigned pin61[] = { 61, };
+static const unsigned pin62[] = { 62, };
+static const unsigned pin63[] = { 63, };
+static const unsigned pin143[] = { 143, };
+static const unsigned pin144[] = { 144, };
+static const unsigned pin145[] = { 145, };
+static const unsigned pin146[] = { 146, };
+static const unsigned pin147[] = { 147, };
+static const unsigned pin148[] = { 148, };
+static const unsigned pin149[] = { 149, };
+static const unsigned pin150[] = { 150, };
+static const unsigned pin151[] = { 151, };
+static const unsigned pin152[] = { 152, };
+static const unsigned pin205[] = { 205, };
+static const unsigned pin206[] = { 206, };
+static const unsigned pin211[] = { 211, };
+static const unsigned pin212[] = { 212, };
+static const unsigned pin213[] = { 213, };
+static const unsigned pin214[] = { 214, };
+static const unsigned pin215[] = { 215, };
+static const unsigned pin216[] = { 216, };
+static const unsigned pin217[] = { 217, };
+static const unsigned pin218[] = { 218, };
+static const unsigned pin219[] = { 219, };
+static const unsigned pin220[] = { 220, };
+static const unsigned pin221[] = { 221, };
+static const unsigned pin222[] = { 222, };
+static const unsigned pin223[] = { 223, };
+static const unsigned pin224[] = { 224, };
+static const unsigned pin225[] = { 225, };
+static const unsigned pin226[] = { 226, };
+static const unsigned pin227[] = { 227, };
+static const unsigned pin228[] = { 228, };
+static const unsigned pin229[] = { 229, };
+static const unsigned pin230[] = { 230, };
+static const unsigned pin231[] = { 231, };
+static const unsigned pin232[] = { 232, };
+static const unsigned pin233[] = { 233, };
+static const unsigned pin234[] = { 234, };
+static const unsigned pin235[] = { 235, };
+static const unsigned pin236[] = { 236, };
+static const unsigned pin237[] = { 237, };
+static const unsigned pin238[] = { 238, };
+static const unsigned pin239[] = { 239, };
+static const unsigned pin240[] = { 240, };
+static const unsigned pin241[] = { 241, };
+static const unsigned pin242[] = { 242, };
+static const unsigned pin243[] = { 243, };
+static const unsigned pin244[] = { 244, };
+static const unsigned pin245[] = { 245, };
+
+static const unsigned pin_grp0[] = { 173, 174, };
+static const unsigned pin_grp1[] = { 175, 185, 188, 197, 198, };
+static const unsigned pin_grp2[] = { 176, 177, 178, 179, 184, 186, 187, 189,
+ 190, 191, 192, };
+static const unsigned pin_grp3[] = { 180, 181, 182, 183, 193, 194, 195, 196, };
+static const unsigned pin_grp4[] = { 199, 200, };
+static const unsigned pin_grp5[] = { 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, };
+static const unsigned pin_grp6[] = { 86, 87, 88, 89, 90, 91, 92, 93, };
+static const unsigned pin_grp7[] = { 98, 99, };
+static const unsigned pin_grp8[] = { 158, 159, 160, 161, 162, 163, 164, 165,
+ 166, 167, 168, 169, 170, 171, 172, };
+
+/* Define muxreg arrays */
+DEFINE_2_MUXREG(i2c0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_I2C0_MASK, 0, 1);
+DEFINE_2_MUXREG(ssp0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_SSP0_MASK, 0, 1);
+DEFINE_2_MUXREG(ssp0_cs0_pins, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_SSP0_CS0_MASK, 0, 1);
+DEFINE_2_MUXREG(ssp0_cs1_2_pins, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_SSP0_CS1_2_MASK, 0, 1);
+DEFINE_2_MUXREG(i2s0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_I2S0_MASK, 0, 1);
+DEFINE_2_MUXREG(i2s1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_I2S1_MASK, 0, 1);
+DEFINE_2_MUXREG(clcd_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_CLCD1_MASK, 0, 1);
+DEFINE_2_MUXREG(clcd_high_res_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_CLCD2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin18, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO15_MASK, 0, 1);
+DEFINE_2_MUXREG(pin19, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO14_MASK, 0, 1);
+DEFINE_2_MUXREG(pin20, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO13_MASK, 0, 1);
+DEFINE_2_MUXREG(pin21, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO12_MASK, 0, 1);
+DEFINE_2_MUXREG(pin22, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO11_MASK, 0, 1);
+DEFINE_2_MUXREG(pin23, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO10_MASK, 0, 1);
+DEFINE_2_MUXREG(pin143, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO00_MASK, 0, 1);
+DEFINE_2_MUXREG(pin144, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO01_MASK, 0, 1);
+DEFINE_2_MUXREG(pin145, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO02_MASK, 0, 1);
+DEFINE_2_MUXREG(pin146, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO03_MASK, 0, 1);
+DEFINE_2_MUXREG(pin147, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO04_MASK, 0, 1);
+DEFINE_2_MUXREG(pin148, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO05_MASK, 0, 1);
+DEFINE_2_MUXREG(pin149, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO06_MASK, 0, 1);
+DEFINE_2_MUXREG(pin150, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO07_MASK, 0, 1);
+DEFINE_2_MUXREG(pin151, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO08_MASK, 0, 1);
+DEFINE_2_MUXREG(pin152, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO09_MASK, 0, 1);
+DEFINE_2_MUXREG(smi_2_chips_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_SMI_MASK, 0, 1);
+DEFINE_2_MUXREG(pin54, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_SMINCS3_MASK, 0, 1);
+DEFINE_2_MUXREG(pin55, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_SMINCS2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin56, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NFRSTPWDWN3_MASK, 0, 1);
+DEFINE_2_MUXREG(pin57, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin58, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin59, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN0_MASK, 0, 1);
+DEFINE_2_MUXREG(pin60, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFWPRT3_MASK, 0, 1);
+DEFINE_2_MUXREG(pin61, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFCE3_MASK, 0, 1);
+DEFINE_2_MUXREG(pin62, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD25_MASK, 0, 1);
+DEFINE_2_MUXREG(pin63, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD24_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp0, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIICLK_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp1, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIICOL_CRS_XFERER_MIITXCLK_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp2, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_RXCLK_RDV_TXEN_D03_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp3, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIID47_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp4, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_MDC_MDIO_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp5, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD23_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp6, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_MCI_DATA8_15_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp7, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NFCE2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp8, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NAND8_MASK, 0, 1);
+DEFINE_2_MUXREG(nand_16bit_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NAND16BIT_1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin205, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_COL1_MASK | PMX_NFCE1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin206, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_COL0_MASK | PMX_NFCE2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin211, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROW1_MASK | PMX_NFWPRT1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin212, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROW0_MASK | PMX_NFWPRT2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin213, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA0_MASK, 0, 1);
+DEFINE_2_MUXREG(pin214, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin215, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin216, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA3_MASK, 0, 1);
+DEFINE_2_MUXREG(pin217, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA4_MASK, 0, 1);
+DEFINE_2_MUXREG(pin218, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA5_MASK, 0, 1);
+DEFINE_2_MUXREG(pin219, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA6_MASK, 0, 1);
+DEFINE_2_MUXREG(pin220, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA7_MASK, 0, 1);
+DEFINE_2_MUXREG(pin221, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA1SD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin222, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA2SD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin223, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA3SD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin224, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR0ALE_MASK, 0, 1);
+DEFINE_2_MUXREG(pin225, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR1CLECLK_MASK, 0, 1);
+DEFINE_2_MUXREG(pin226, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin227, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICECF_MASK, 0, 1);
+DEFINE_2_MUXREG(pin228, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICEXD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin229, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICESDMMC_MASK, 0, 1);
+DEFINE_2_MUXREG(pin230, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDCF1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin231, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDCF2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin232, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDXD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin233, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDSDMMC_MASK, 0, 1);
+DEFINE_2_MUXREG(pin234, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATADIR_MASK, 0, 1);
+DEFINE_2_MUXREG(pin235, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDMARQWP_MASK, 0, 1);
+DEFINE_2_MUXREG(pin236, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIORDRE_MASK, 0, 1);
+DEFINE_2_MUXREG(pin237, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIOWRWE_MASK, 0, 1);
+DEFINE_2_MUXREG(pin238, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIRESETCF_MASK, 0, 1);
+DEFINE_2_MUXREG(pin239, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICS0CE_MASK, 0, 1);
+DEFINE_2_MUXREG(pin240, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICFINTR_MASK, 0, 1);
+DEFINE_2_MUXREG(pin241, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIORDY_MASK, 0, 1);
+DEFINE_2_MUXREG(pin242, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICS1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin243, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDMAACK_MASK, 0, 1);
+DEFINE_2_MUXREG(pin244, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCISDCMD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin245, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCILEDS_MASK, 0, 1);
+DEFINE_2_MUXREG(keyboard_rowcol6_8_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROWCOL68_MASK, 0, 1);
+DEFINE_2_MUXREG(uart0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_UART0_MASK, 0, 1);
+DEFINE_2_MUXREG(uart0_modem_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_UART0_MODEM_MASK, 0, 1);
+DEFINE_2_MUXREG(gpt0_tmr0_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT0_TMR0_MASK, 0, 1);
+DEFINE_2_MUXREG(gpt0_tmr1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT0_TMR1_MASK, 0, 1);
+DEFINE_2_MUXREG(gpt1_tmr0_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT1_TMR0_MASK, 0, 1);
+DEFINE_2_MUXREG(gpt1_tmr1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT1_TMR1_MASK, 0, 1);
+DEFINE_2_MUXREG(touch_xy_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_TOUCH_XY_MASK, 0, 1);
+
+static struct spear_gpio_pingroup spear1310_gpio_pingroup[] = {
+ GPIO_PINGROUP(i2c0_pins),
+ GPIO_PINGROUP(ssp0_pins),
+ GPIO_PINGROUP(ssp0_cs0_pins),
+ GPIO_PINGROUP(ssp0_cs1_2_pins),
+ GPIO_PINGROUP(i2s0_pins),
+ GPIO_PINGROUP(i2s1_pins),
+ GPIO_PINGROUP(clcd_pins),
+ GPIO_PINGROUP(clcd_high_res_pins),
+ GPIO_PINGROUP(pin18),
+ GPIO_PINGROUP(pin19),
+ GPIO_PINGROUP(pin20),
+ GPIO_PINGROUP(pin21),
+ GPIO_PINGROUP(pin22),
+ GPIO_PINGROUP(pin23),
+ GPIO_PINGROUP(pin143),
+ GPIO_PINGROUP(pin144),
+ GPIO_PINGROUP(pin145),
+ GPIO_PINGROUP(pin146),
+ GPIO_PINGROUP(pin147),
+ GPIO_PINGROUP(pin148),
+ GPIO_PINGROUP(pin149),
+ GPIO_PINGROUP(pin150),
+ GPIO_PINGROUP(pin151),
+ GPIO_PINGROUP(pin152),
+ GPIO_PINGROUP(smi_2_chips_pins),
+ GPIO_PINGROUP(pin54),
+ GPIO_PINGROUP(pin55),
+ GPIO_PINGROUP(pin56),
+ GPIO_PINGROUP(pin57),
+ GPIO_PINGROUP(pin58),
+ GPIO_PINGROUP(pin59),
+ GPIO_PINGROUP(pin60),
+ GPIO_PINGROUP(pin61),
+ GPIO_PINGROUP(pin62),
+ GPIO_PINGROUP(pin63),
+ GPIO_PINGROUP(pin_grp0),
+ GPIO_PINGROUP(pin_grp1),
+ GPIO_PINGROUP(pin_grp2),
+ GPIO_PINGROUP(pin_grp3),
+ GPIO_PINGROUP(pin_grp4),
+ GPIO_PINGROUP(pin_grp5),
+ GPIO_PINGROUP(pin_grp6),
+ GPIO_PINGROUP(pin_grp7),
+ GPIO_PINGROUP(pin_grp8),
+ GPIO_PINGROUP(nand_16bit_pins),
+ GPIO_PINGROUP(pin205),
+ GPIO_PINGROUP(pin206),
+ GPIO_PINGROUP(pin211),
+ GPIO_PINGROUP(pin212),
+ GPIO_PINGROUP(pin213),
+ GPIO_PINGROUP(pin214),
+ GPIO_PINGROUP(pin215),
+ GPIO_PINGROUP(pin216),
+ GPIO_PINGROUP(pin217),
+ GPIO_PINGROUP(pin218),
+ GPIO_PINGROUP(pin219),
+ GPIO_PINGROUP(pin220),
+ GPIO_PINGROUP(pin221),
+ GPIO_PINGROUP(pin222),
+ GPIO_PINGROUP(pin223),
+ GPIO_PINGROUP(pin224),
+ GPIO_PINGROUP(pin225),
+ GPIO_PINGROUP(pin226),
+ GPIO_PINGROUP(pin227),
+ GPIO_PINGROUP(pin228),
+ GPIO_PINGROUP(pin229),
+ GPIO_PINGROUP(pin230),
+ GPIO_PINGROUP(pin231),
+ GPIO_PINGROUP(pin232),
+ GPIO_PINGROUP(pin233),
+ GPIO_PINGROUP(pin234),
+ GPIO_PINGROUP(pin235),
+ GPIO_PINGROUP(pin236),
+ GPIO_PINGROUP(pin237),
+ GPIO_PINGROUP(pin238),
+ GPIO_PINGROUP(pin239),
+ GPIO_PINGROUP(pin240),
+ GPIO_PINGROUP(pin241),
+ GPIO_PINGROUP(pin242),
+ GPIO_PINGROUP(pin243),
+ GPIO_PINGROUP(pin244),
+ GPIO_PINGROUP(pin245),
+ GPIO_PINGROUP(keyboard_rowcol6_8_pins),
+ GPIO_PINGROUP(uart0_pins),
+ GPIO_PINGROUP(uart0_modem_pins),
+ GPIO_PINGROUP(gpt0_tmr0_pins),
+ GPIO_PINGROUP(gpt0_tmr1_pins),
+ GPIO_PINGROUP(gpt1_tmr0_pins),
+ GPIO_PINGROUP(gpt1_tmr1_pins),
+ GPIO_PINGROUP(touch_xy_pins),
+};
+
static struct spear_pinctrl_machdata spear1310_machdata = {
.pins = spear1310_pins,
.npins = ARRAY_SIZE(spear1310_pins),
@@ -2425,6 +2687,8 @@ static struct spear_pinctrl_machdata spear1310_machdata = {
.ngroups = ARRAY_SIZE(spear1310_pingroups),
.functions = spear1310_functions,
.nfunctions = ARRAY_SIZE(spear1310_functions),
+ .gpio_pingroups = spear1310_gpio_pingroup,
+ .ngpio_pingroups = ARRAY_SIZE(spear1310_gpio_pingroup),
.modes_supported = false,
};
diff --git a/drivers/pinctrl/spear/pinctrl-spear1340.c b/drivers/pinctrl/spear/pinctrl-spear1340.c
index 0606b8cf3f2c..0b4af0e5cdc1 100644
--- a/drivers/pinctrl/spear/pinctrl-spear1340.c
+++ b/drivers/pinctrl/spear/pinctrl-spear1340.c
@@ -1971,6 +1971,32 @@ static struct spear_function *spear1340_functions[] = {
&sata_function,
};
+static void gpio_request_endisable(struct spear_pmx *pmx, int pin,
+ bool enable)
+{
+ unsigned int regoffset, regindex, bitoffset;
+ unsigned int val;
+
+ /* pin++ as gpio configuration starts from 2nd bit of base register */
+ pin++;
+
+ regindex = pin / 32;
+ bitoffset = pin % 32;
+
+ if (regindex <= 3)
+ regoffset = PAD_FUNCTION_EN_1 + regindex * sizeof(int *);
+ else
+ regoffset = PAD_FUNCTION_EN_5 + (regindex - 4) * sizeof(int *);
+
+ val = pmx_readl(pmx, regoffset);
+ if (enable)
+ val &= ~(0x1 << bitoffset);
+ else
+ val |= 0x1 << bitoffset;
+
+ pmx_writel(pmx, val, regoffset);
+}
+
static struct spear_pinctrl_machdata spear1340_machdata = {
.pins = spear1340_pins,
.npins = ARRAY_SIZE(spear1340_pins),
@@ -1978,6 +2004,7 @@ static struct spear_pinctrl_machdata spear1340_machdata = {
.ngroups = ARRAY_SIZE(spear1340_pingroups),
.functions = spear1340_functions,
.nfunctions = ARRAY_SIZE(spear1340_functions),
+ .gpio_request_endisable = gpio_request_endisable,
.modes_supported = false,
};
diff --git a/drivers/pinctrl/spear/pinctrl-spear300.c b/drivers/pinctrl/spear/pinctrl-spear300.c
index 4dfc2849b172..9a491007f42d 100644
--- a/drivers/pinctrl/spear/pinctrl-spear300.c
+++ b/drivers/pinctrl/spear/pinctrl-spear300.c
@@ -661,6 +661,8 @@ static int __devinit spear300_pinctrl_probe(struct platform_device *pdev)
spear3xx_machdata.ngroups = ARRAY_SIZE(spear300_pingroups);
spear3xx_machdata.functions = spear300_functions;
spear3xx_machdata.nfunctions = ARRAY_SIZE(spear300_functions);
+ spear3xx_machdata.gpio_pingroups = NULL;
+ spear3xx_machdata.ngpio_pingroups = 0;
spear3xx_machdata.modes_supported = true;
spear3xx_machdata.pmx_modes = spear300_pmx_modes;
diff --git a/drivers/pinctrl/spear/pinctrl-spear310.c b/drivers/pinctrl/spear/pinctrl-spear310.c
index 96883693fb7e..4d5dfe9c760a 100644
--- a/drivers/pinctrl/spear/pinctrl-spear310.c
+++ b/drivers/pinctrl/spear/pinctrl-spear310.c
@@ -388,6 +388,8 @@ static int __devinit spear310_pinctrl_probe(struct platform_device *pdev)
spear3xx_machdata.nfunctions = ARRAY_SIZE(spear310_functions);
pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG);
+ pmx_init_gpio_pingroup_addr(spear3xx_machdata.gpio_pingroups,
+ spear3xx_machdata.ngpio_pingroups, PMX_CONFIG_REG);
spear3xx_machdata.modes_supported = false;
diff --git a/drivers/pinctrl/spear/pinctrl-spear320.c b/drivers/pinctrl/spear/pinctrl-spear320.c
index ca47b0e50780..c996e26e3b6c 100644
--- a/drivers/pinctrl/spear/pinctrl-spear320.c
+++ b/drivers/pinctrl/spear/pinctrl-spear320.c
@@ -3431,6 +3431,8 @@ static int __devinit spear320_pinctrl_probe(struct platform_device *pdev)
spear3xx_machdata.npmx_modes = ARRAY_SIZE(spear320_pmx_modes);
pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG);
+ pmx_init_gpio_pingroup_addr(spear3xx_machdata.gpio_pingroups,
+ spear3xx_machdata.ngpio_pingroups, PMX_CONFIG_REG);
ret = spear_pinctrl_probe(pdev, &spear3xx_machdata);
if (ret)
diff --git a/drivers/pinctrl/spear/pinctrl-spear3xx.c b/drivers/pinctrl/spear/pinctrl-spear3xx.c
index 0242378f7cb8..12ee21af766b 100644
--- a/drivers/pinctrl/spear/pinctrl-spear3xx.c
+++ b/drivers/pinctrl/spear/pinctrl-spear3xx.c
@@ -481,7 +481,44 @@ struct spear_function spear3xx_timer_2_3_function = {
.ngroups = ARRAY_SIZE(timer_2_3_grps),
};
+/* Define muxreg arrays */
+DEFINE_MUXREG(firda_pins, 0, PMX_FIRDA_MASK, 0);
+DEFINE_MUXREG(i2c_pins, 0, PMX_I2C_MASK, 0);
+DEFINE_MUXREG(ssp_cs_pins, 0, PMX_SSP_CS_MASK, 0);
+DEFINE_MUXREG(ssp_pins, 0, PMX_SSP_MASK, 0);
+DEFINE_MUXREG(mii_pins, 0, PMX_MII_MASK, 0);
+DEFINE_MUXREG(gpio0_pin0_pins, 0, PMX_GPIO_PIN0_MASK, 0);
+DEFINE_MUXREG(gpio0_pin1_pins, 0, PMX_GPIO_PIN1_MASK, 0);
+DEFINE_MUXREG(gpio0_pin2_pins, 0, PMX_GPIO_PIN2_MASK, 0);
+DEFINE_MUXREG(gpio0_pin3_pins, 0, PMX_GPIO_PIN3_MASK, 0);
+DEFINE_MUXREG(gpio0_pin4_pins, 0, PMX_GPIO_PIN4_MASK, 0);
+DEFINE_MUXREG(gpio0_pin5_pins, 0, PMX_GPIO_PIN5_MASK, 0);
+DEFINE_MUXREG(uart0_ext_pins, 0, PMX_UART0_MODEM_MASK, 0);
+DEFINE_MUXREG(uart0_pins, 0, PMX_UART0_MASK, 0);
+DEFINE_MUXREG(timer_0_1_pins, 0, PMX_TIMER_0_1_MASK, 0);
+DEFINE_MUXREG(timer_2_3_pins, 0, PMX_TIMER_2_3_MASK, 0);
+
+static struct spear_gpio_pingroup spear3xx_gpio_pingroup[] = {
+ GPIO_PINGROUP(firda_pins),
+ GPIO_PINGROUP(i2c_pins),
+ GPIO_PINGROUP(ssp_cs_pins),
+ GPIO_PINGROUP(ssp_pins),
+ GPIO_PINGROUP(mii_pins),
+ GPIO_PINGROUP(gpio0_pin0_pins),
+ GPIO_PINGROUP(gpio0_pin1_pins),
+ GPIO_PINGROUP(gpio0_pin2_pins),
+ GPIO_PINGROUP(gpio0_pin3_pins),
+ GPIO_PINGROUP(gpio0_pin4_pins),
+ GPIO_PINGROUP(gpio0_pin5_pins),
+ GPIO_PINGROUP(uart0_ext_pins),
+ GPIO_PINGROUP(uart0_pins),
+ GPIO_PINGROUP(timer_0_1_pins),
+ GPIO_PINGROUP(timer_2_3_pins),
+};
+
struct spear_pinctrl_machdata spear3xx_machdata = {
.pins = spear3xx_pins,
.npins = ARRAY_SIZE(spear3xx_pins),
+ .gpio_pingroups = spear3xx_gpio_pingroup,
+ .ngpio_pingroups = ARRAY_SIZE(spear3xx_gpio_pingroup),
};
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index e7a4780e93db..9e198e590675 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -120,15 +120,11 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
return vq;
}
-static void rproc_virtio_del_vqs(struct virtio_device *vdev)
+static void __rproc_virtio_del_vqs(struct virtio_device *vdev)
{
struct virtqueue *vq, *n;
- struct rproc *rproc = vdev_to_rproc(vdev);
struct rproc_vring *rvring;
- /* power down the remote processor before deleting vqs */
- rproc_shutdown(rproc);
-
list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
rvring = vq->priv;
rvring->vq = NULL;
@@ -137,6 +133,16 @@ static void rproc_virtio_del_vqs(struct virtio_device *vdev)
}
}
+static void rproc_virtio_del_vqs(struct virtio_device *vdev)
+{
+ struct rproc *rproc = vdev_to_rproc(vdev);
+
+ /* power down the remote processor before deleting vqs */
+ rproc_shutdown(rproc);
+
+ __rproc_virtio_del_vqs(vdev);
+}
+
static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[],
vq_callback_t *callbacks[],
@@ -163,7 +169,7 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs,
return 0;
error:
- rproc_virtio_del_vqs(vdev);
+ __rproc_virtio_del_vqs(vdev);
return ret;
}
diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c
index 7a82337e4dee..073108dcf9e7 100644
--- a/drivers/rtc/rtc-tps65910.c
+++ b/drivers/rtc/rtc-tps65910.c
@@ -288,11 +288,11 @@ static int __devinit tps65910_rtc_probe(struct platform_device *pdev)
static int __devexit tps65910_rtc_remove(struct platform_device *pdev)
{
/* leave rtc running, but disable irqs */
- struct rtc_device *rtc = platform_get_drvdata(pdev);
+ struct tps65910_rtc *tps_rtc = platform_get_drvdata(pdev);
- tps65910_rtc_alarm_irq_enable(&rtc->dev, 0);
+ tps65910_rtc_alarm_irq_enable(&pdev->dev, 0);
- rtc_device_unregister(rtc);
+ rtc_device_unregister(tps_rtc->rtc);
return 0;
}
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 16b7a72a70c4..3b2365c8eab2 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -1276,7 +1276,7 @@ struct megasas_evt_detail {
} __attribute__ ((packed));
struct megasas_aen_event {
- struct work_struct hotplug_work;
+ struct delayed_work hotplug_work;
struct megasas_instance *instance;
};
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index d2c5366aff7f..e4f2baacf1e1 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -2060,9 +2060,9 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
} else {
ev->instance = instance;
instance->ev = ev;
- INIT_WORK(&ev->hotplug_work, megasas_aen_polling);
- schedule_delayed_work(
- (struct delayed_work *)&ev->hotplug_work, 0);
+ INIT_DELAYED_WORK(&ev->hotplug_work,
+ megasas_aen_polling);
+ schedule_delayed_work(&ev->hotplug_work, 0);
}
}
}
@@ -4352,8 +4352,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
/* cancel the delayed work if this work still in queue */
if (instance->ev != NULL) {
struct megasas_aen_event *ev = instance->ev;
- cancel_delayed_work_sync(
- (struct delayed_work *)&ev->hotplug_work);
+ cancel_delayed_work_sync(&ev->hotplug_work);
instance->ev = NULL;
}
@@ -4545,8 +4544,7 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
/* cancel the delayed work if this work still in queue*/
if (instance->ev != NULL) {
struct megasas_aen_event *ev = instance->ev;
- cancel_delayed_work_sync(
- (struct delayed_work *)&ev->hotplug_work);
+ cancel_delayed_work_sync(&ev->hotplug_work);
instance->ev = NULL;
}
@@ -5190,7 +5188,7 @@ static void
megasas_aen_polling(struct work_struct *work)
{
struct megasas_aen_event *ev =
- container_of(work, struct megasas_aen_event, hotplug_work);
+ container_of(work, struct megasas_aen_event, hotplug_work.work);
struct megasas_instance *instance = ev->instance;
union megasas_evt_class_locale class_locale;
struct Scsi_Host *host;
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 9097155e9ebe..dcecbfb17243 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1819,8 +1819,10 @@ void target_execute_cmd(struct se_cmd *cmd)
/*
* If the received CDB has aleady been aborted stop processing it here.
*/
- if (transport_check_aborted_status(cmd, 1))
+ if (transport_check_aborted_status(cmd, 1)) {
+ complete(&cmd->t_transport_stop_comp);
return;
+ }
/*
* Determine if IOCTL context caller in requesting the stopping of this
@@ -3067,7 +3069,7 @@ void transport_send_task_abort(struct se_cmd *cmd)
unsigned long flags;
spin_lock_irqsave(&cmd->t_state_lock, flags);
- if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
+ if (cmd->se_cmd_flags & (SCF_SENT_CHECK_CONDITION | SCF_SENT_DELAYED_TAS)) {
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
return;
}
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 3d7e1ee2fa57..65f891be12d1 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -39,6 +39,7 @@
#include <linux/atmel_pdc.h>
#include <linux/atmel_serial.h>
#include <linux/uaccess.h>
+#include <linux/pinctrl/consumer.h>
#include <asm/io.h>
#include <asm/ioctls.h>
@@ -1773,6 +1774,7 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
struct atmel_uart_data *pdata = pdev->dev.platform_data;
void *data;
int ret = -ENODEV;
+ struct pinctrl *pinctrl;
BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
@@ -1805,6 +1807,12 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
atmel_init_port(port, pdev);
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto err;
+ }
+
if (!atmel_use_dma_rx(&port->uart)) {
ret = -ENOMEM;
data = kmalloc(sizeof(struct atmel_uart_char)
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index f87d7e8964bf..4e0d0c3734b3 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -539,25 +539,25 @@ static void insert_char(struct vc_data *vc, unsigned int nr)
{
unsigned short *p = (unsigned short *) vc->vc_pos;
- scr_memmovew(p + nr, p, vc->vc_cols - vc->vc_x);
+ scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x) * 2);
scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
vc->vc_need_wrap = 0;
if (DO_UPDATE(vc))
do_update_region(vc, (unsigned long) p,
- (vc->vc_cols - vc->vc_x) / 2 + 1);
+ vc->vc_cols - vc->vc_x);
}
static void delete_char(struct vc_data *vc, unsigned int nr)
{
unsigned short *p = (unsigned short *) vc->vc_pos;
- scr_memcpyw(p, p + nr, vc->vc_cols - vc->vc_x - nr);
+ scr_memcpyw(p, p + nr, (vc->vc_cols - vc->vc_x - nr) * 2);
scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char,
nr * 2);
vc->vc_need_wrap = 0;
if (DO_UPDATE(vc))
do_update_region(vc, (unsigned long) p,
- (vc->vc_cols - vc->vc_x) / 2);
+ vc->vc_cols - vc->vc_x);
}
static int softcursor_original;
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 99ac2cb08b43..dedaf81d8f36 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -1076,7 +1076,7 @@ static int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
}
_iov = iov + ret;
size = reg->memory_size - addr + reg->guest_phys_addr;
- _iov->iov_len = min((u64)len, size);
+ _iov->iov_len = min((u64)len - s, size);
_iov->iov_base = (void __user *)(unsigned long)
(reg->userspace_addr + addr - reg->guest_phys_addr);
s += size;