diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/dma/imx-dma.c | 3 | ||||
| -rw-r--r-- | drivers/dma/imx-sdma.c | 6 | ||||
| -rw-r--r-- | drivers/gpio/74x164.c (renamed from drivers/gpio/gpio-74x164.c) | 33 | ||||
| -rw-r--r-- | drivers/gpio/Kconfig | 66 | ||||
| -rw-r--r-- | drivers/gpio/Makefile | 87 | ||||
| -rw-r--r-- | drivers/gpio/ab8500-gpio.c (renamed from drivers/gpio/gpio-ab8500.c) | 0 | ||||
| -rw-r--r-- | drivers/gpio/adp5520-gpio.c (renamed from drivers/gpio/gpio-adp5520.c) | 0 | ||||
| -rw-r--r-- | drivers/gpio/adp5588-gpio.c (renamed from drivers/gpio/gpio-adp5588.c) | 0 | ||||
| -rw-r--r-- | drivers/gpio/basic_mmio_gpio.c (renamed from drivers/gpio/gpio-generic.c) | 6 | ||||
| -rw-r--r-- | drivers/gpio/bt8xxgpio.c (renamed from drivers/gpio/gpio-bt8xx.c) | 0 | ||||
| -rw-r--r-- | drivers/gpio/cs5535-gpio.c (renamed from drivers/gpio/gpio-cs5535.c) | 0 | ||||
| -rw-r--r-- | drivers/gpio/gpio-da9052.c | 277 | ||||
| -rw-r--r-- | drivers/gpio/gpio-ep93xx.c | 405 | ||||
| -rw-r--r-- | drivers/gpio/gpio-exynos4.c | 5 | ||||
| -rw-r--r-- | drivers/gpio/gpio-mpc5200.c | 376 | ||||
| -rw-r--r-- | drivers/gpio/gpio-mxc.c | 460 | ||||
| -rw-r--r-- | drivers/gpio/gpio-mxs.c | 289 | ||||
| -rw-r--r-- | drivers/gpio/gpio-omap.c | 723 | ||||
| -rw-r--r-- | drivers/gpio/gpio-plat-samsung.c | 3 | ||||
| -rw-r--r-- | drivers/gpio/gpio-s5pc100.c | 5 | ||||
| -rw-r--r-- | drivers/gpio/gpio-s5pv210.c | 5 | ||||
| -rw-r--r-- | drivers/gpio/gpio-tegra.c | 441 | ||||
| -rw-r--r-- | drivers/gpio/gpio-u300.c | 5 | ||||
| -rw-r--r-- | drivers/gpio/it8761e_gpio.c (renamed from drivers/gpio/gpio-it8761e.c) | 2 | ||||
| -rw-r--r-- | drivers/gpio/janz-ttl.c (renamed from drivers/gpio/gpio-janz-ttl.c) | 0 | ||||
| -rw-r--r-- | drivers/gpio/langwell_gpio.c (renamed from drivers/gpio/gpio-langwell.c) | 4 | ||||
| -rw-r--r-- | drivers/gpio/max7300.c (renamed from drivers/gpio/gpio-max7300.c) | 2 | ||||
| -rw-r--r-- | drivers/gpio/max7301.c (renamed from drivers/gpio/gpio-max7301.c) | 2 | ||||
| -rw-r--r-- | drivers/gpio/max730x.c (renamed from drivers/gpio/gpio-max730x.c) | 2 | ||||
| -rw-r--r-- | drivers/gpio/max732x.c (renamed from drivers/gpio/gpio-max732x.c) | 2 | ||||
| -rw-r--r-- | drivers/gpio/mc33880.c (renamed from drivers/gpio/gpio-mc33880.c) | 2 | ||||
| -rw-r--r-- | drivers/gpio/mcp23s08.c (renamed from drivers/gpio/gpio-mcp23s08.c) | 291 | ||||
| -rw-r--r-- | drivers/gpio/ml_ioh_gpio.c (renamed from drivers/gpio/gpio-ml-ioh.c) | 2 | ||||
| -rw-r--r-- | drivers/gpio/pca953x.c (renamed from drivers/gpio/gpio-pca953x.c) | 105 | ||||
| -rw-r--r-- | drivers/gpio/pcf857x.c (renamed from drivers/gpio/gpio-pcf857x.c) | 2 | ||||
| -rw-r--r-- | drivers/gpio/pch_gpio.c (renamed from drivers/gpio/gpio-pch.c) | 0 | ||||
| -rw-r--r-- | drivers/gpio/pl061.c (renamed from drivers/gpio/gpio-pl061.c) | 4 | ||||
| -rw-r--r-- | drivers/gpio/rdc321x-gpio.c (renamed from drivers/gpio/gpio-rdc321x.c) | 0 | ||||
| -rw-r--r-- | drivers/gpio/sch_gpio.c (renamed from drivers/gpio/gpio-sch.c) | 2 | ||||
| -rw-r--r-- | drivers/gpio/stmpe-gpio.c (renamed from drivers/gpio/gpio-stmpe.c) | 0 | ||||
| -rw-r--r-- | drivers/gpio/sx150x.c (renamed from drivers/gpio/gpio-sx150x.c) | 0 | ||||
| -rw-r--r-- | drivers/gpio/tc3589x-gpio.c (renamed from drivers/gpio/gpio-tc3589x.c) | 0 | ||||
| -rw-r--r-- | drivers/gpio/timbgpio.c (renamed from drivers/gpio/gpio-timberdale.c) | 2 | ||||
| -rw-r--r-- | drivers/gpio/tps65910-gpio.c (renamed from drivers/gpio/gpio-tps65910.c) | 2 | ||||
| -rw-r--r-- | drivers/gpio/twl4030-gpio.c (renamed from drivers/gpio/gpio-twl4030.c) | 2 | ||||
| -rw-r--r-- | drivers/gpio/ucb1400_gpio.c (renamed from drivers/gpio/gpio-ucb1400.c) | 0 | ||||
| -rw-r--r-- | drivers/gpio/vr41xx_giu.c (renamed from drivers/gpio/gpio-vr41xx.c) | 2 | ||||
| -rw-r--r-- | drivers/gpio/vx855_gpio.c (renamed from drivers/gpio/gpio-vx855.c) | 0 | ||||
| -rw-r--r-- | drivers/gpio/wm831x-gpio.c (renamed from drivers/gpio/gpio-wm831x.c) | 2 | ||||
| -rw-r--r-- | drivers/gpio/wm8350-gpiolib.c (renamed from drivers/gpio/gpio-wm8350.c) | 2 | ||||
| -rw-r--r-- | drivers/gpio/wm8994-gpio.c (renamed from drivers/gpio/gpio-wm8994.c) | 2 | ||||
| -rw-r--r-- | drivers/gpio/xilinx_gpio.c (renamed from drivers/gpio/gpio-xilinx.c) | 0 | ||||
| -rw-r--r-- | drivers/input/misc/Kconfig | 13 | ||||
| -rw-r--r-- | drivers/input/misc/Makefile | 1 | ||||
| -rw-r--r-- | drivers/input/misc/twl4030-vibra.c | 12 | ||||
| -rw-r--r-- | drivers/input/misc/twl6040-vibra.c | 423 | ||||
| -rw-r--r-- | drivers/leds/Kconfig | 19 | ||||
| -rw-r--r-- | drivers/leds/leds-gpio.c | 6 | ||||
| -rw-r--r-- | drivers/mfd/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/mfd/Makefile | 3 | ||||
| -rw-r--r-- | drivers/mfd/twl-core.c | 13 | ||||
| -rw-r--r-- | drivers/mfd/twl4030-audio.c | 277 | ||||
| -rw-r--r-- | drivers/mfd/twl4030-codec.c | 277 | ||||
| -rw-r--r-- | drivers/mfd/twl6040-core.c | 620 | ||||
| -rw-r--r-- | drivers/mfd/twl6040-irq.c | 191 | ||||
| -rw-r--r-- | drivers/mmc/host/mxcmmc.c | 8 | ||||
| -rw-r--r-- | drivers/of/gpio.c | 11 | ||||
| -rw-r--r-- | drivers/pcmcia/pxa2xx_sharpsl.c | 3 | ||||
| -rw-r--r-- | drivers/pcmcia/pxa2xx_trizeps4.c | 4 | ||||
| -rw-r--r-- | drivers/tty/serial/Kconfig | 15 | ||||
| -rw-r--r-- | drivers/tty/serial/Makefile | 2 | ||||
| -rw-r--r-- | drivers/tty/serial/s3c2400.c | 105 | ||||
| -rw-r--r-- | drivers/tty/serial/s3c24a0.c | 117 | ||||
| -rw-r--r-- | drivers/video/omap2/displays/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/video/omap2/displays/Makefile | 1 | ||||
| -rw-r--r-- | drivers/video/omap2/displays/panel-picodlp.c | 591 | ||||
| -rw-r--r-- | drivers/video/omap2/displays/panel-picodlp.h | 288 | ||||
| -rw-r--r-- | drivers/video/omap2/displays/panel-taal.c | 50 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/Kconfig | 12 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/core.c | 15 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/dispc.c | 484 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/display.c | 45 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/dpi.c | 73 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/dsi.c | 277 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/dss.c | 584 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/dss.h | 34 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/dss_features.c | 13 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/dss_features.h | 4 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/hdmi.c | 162 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/manager.c | 67 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/overlay.c | 27 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/rfbi.c | 111 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/sdi.c | 40 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/venc.c | 180 | ||||
| -rw-r--r-- | drivers/video/omap2/omapfb/omapfb-ioctl.c | 72 | ||||
| -rw-r--r-- | drivers/video/omap2/omapfb/omapfb-main.c | 166 | ||||
| -rw-r--r-- | drivers/video/omap2/omapfb/omapfb-sysfs.c | 34 | ||||
| -rw-r--r-- | drivers/video/omap2/omapfb/omapfb.h | 37 |
98 files changed, 2554 insertions, 6579 deletions
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index d99f71c356b..e18eaabe92b 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -135,8 +135,7 @@ static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, if (ret) return ret; - imx_dma_config_burstlen(imxdmac->imxdma_channel, - imxdmac->watermark_level * imxdmac->word_size); + imx_dma_config_burstlen(imxdmac->imxdma_channel, imxdmac->watermark_level); return 0; default: diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 1ea47db2ff0..b6d1455fa93 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1105,7 +1105,7 @@ static void sdma_add_scripts(struct sdma_engine *sdma, } static int __init sdma_get_firmware(struct sdma_engine *sdma, - const char *fw_name) + const char *cpu_name, int to_version) { const struct firmware *fw; char *fwname; @@ -1114,7 +1114,7 @@ static int __init sdma_get_firmware(struct sdma_engine *sdma, const struct sdma_script_start_addrs *addr; unsigned short *ram_code; - fwname = kasprintf(GFP_KERNEL, "%s", fw_name); + fwname = kasprintf(GFP_KERNEL, "sdma-%s-to%d.bin", cpu_name, to_version); if (!fwname) return -ENOMEM; @@ -1317,7 +1317,7 @@ static int __init sdma_probe(struct platform_device *pdev) if (pdata->script_addrs) sdma_add_scripts(sdma, pdata->script_addrs); - sdma_get_firmware(sdma, pdata->fw_name); + sdma_get_firmware(sdma, pdata->cpu_name, pdata->to_version); sdma->dma_device.dev = &pdev->dev; diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/74x164.c index ff525c0958d..84e07021983 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/74x164.c @@ -16,6 +16,9 @@ #include <linux/gpio.h> #include <linux/slab.h> +#define GEN_74X164_GPIO_COUNT 8 + + struct gen_74x164_chip { struct spi_device *spi; struct gpio_chip gpio_chip; @@ -23,7 +26,9 @@ struct gen_74x164_chip { u8 port_config; }; -static struct gen_74x164_chip *gpio_to_74x164_chip(struct gpio_chip *gc) +static void gen_74x164_set_value(struct gpio_chip *, unsigned, int); + +static struct gen_74x164_chip *gpio_to_chip(struct gpio_chip *gc) { return container_of(gc, struct gen_74x164_chip, gpio_chip); } @@ -34,9 +39,16 @@ static int __gen_74x164_write_config(struct gen_74x164_chip *chip) &chip->port_config, sizeof(chip->port_config)); } +static int gen_74x164_direction_output(struct gpio_chip *gc, + unsigned offset, int val) +{ + gen_74x164_set_value(gc, offset, val); + return 0; +} + static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset) { - struct gen_74x164_chip *chip = gpio_to_74x164_chip(gc); + struct gen_74x164_chip *chip = gpio_to_chip(gc); int ret; mutex_lock(&chip->lock); @@ -49,7 +61,7 @@ static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset) static void gen_74x164_set_value(struct gpio_chip *gc, unsigned offset, int val) { - struct gen_74x164_chip *chip = gpio_to_74x164_chip(gc); + struct gen_74x164_chip *chip = gpio_to_chip(gc); mutex_lock(&chip->lock); if (val) @@ -61,13 +73,6 @@ static void gen_74x164_set_value(struct gpio_chip *gc, mutex_unlock(&chip->lock); } -static int gen_74x164_direction_output(struct gpio_chip *gc, - unsigned offset, int val) -{ - gen_74x164_set_value(gc, offset, val); - return 0; -} - static int __devinit gen_74x164_probe(struct spi_device *spi) { struct gen_74x164_chip *chip; @@ -99,12 +104,12 @@ static int __devinit gen_74x164_probe(struct spi_device *spi) chip->spi = spi; - chip->gpio_chip.label = spi->modalias; - chip->gpio_chip.direction_output = gen_74x164_direction_output; + chip->gpio_chip.label = GEN_74X164_DRIVER_NAME, + chip->gpio_chip.direction_output = gen_74x164_direction_output; chip->gpio_chip.get = gen_74x164_get_value; chip->gpio_chip.set = gen_74x164_set_value; chip->gpio_chip.base = pdata->base; - chip->gpio_chip.ngpio = 8; + chip->gpio_chip.ngpio = GEN_74X164_GPIO_COUNT; chip->gpio_chip.can_sleep = 1; chip->gpio_chip.dev = &spi->dev; chip->gpio_chip.owner = THIS_MODULE; @@ -152,7 +157,7 @@ static int __devexit gen_74x164_remove(struct spi_device *spi) static struct spi_driver gen_74x164_driver = { .driver = { - .name = "74x164", + .name = GEN_74X164_DRIVER_NAME, .owner = THIS_MODULE, }, .probe = gen_74x164_probe, diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 363498697c2..2967002a9f8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -63,58 +63,33 @@ config GPIO_SYSFS Kernel drivers may also request that a particular GPIO be exported to userspace; this can be useful when debugging. -config GPIO_GENERIC - tristate - # put drivers in the right section, in alphabetical order -config GPIO_DA9052 - tristate "Dialog DA9052 GPIO" - depends on PMIC_DA9052 - help - Say yes here to enable the GPIO driver for the DA9052 chip. - config GPIO_MAX730X tristate comment "Memory mapped GPIO drivers:" -config GPIO_GENERIC_PLATFORM - tristate "Generic memory-mapped GPIO controller support (MMIO platform device)" - select GPIO_GENERIC +config GPIO_BASIC_MMIO_CORE + tristate + help + Provides core functionality for basic memory-mapped GPIO controllers. + +config GPIO_BASIC_MMIO + tristate "Basic memory-mapped GPIO controllers support" + select GPIO_BASIC_MMIO_CORE help - Say yes here to support basic platform_device memory-mapped GPIO controllers. + Say yes here to support basic memory-mapped GPIO controllers. config GPIO_IT8761E tristate "IT8761E GPIO support" help Say yes here to support GPIO functionality of IT8761E super I/O chip. -config GPIO_EP93XX - def_bool y - depends on ARCH_EP93XX - select GPIO_GENERIC - config GPIO_EXYNOS4 def_bool y depends on CPU_EXYNOS4210 -config GPIO_MPC5200 - def_bool y - depends on PPC_MPC52xx - -config GPIO_MXC - def_bool y - depends on ARCH_MXC - select GPIO_GENERIC - select GENERIC_IRQ_CHIP - -config GPIO_MXS - def_bool y - depends on ARCH_MXS - select GPIO_GENERIC - select GENERIC_IRQ_CHIP - config GPIO_PLAT_SAMSUNG def_bool y depends on SAMSUNG_GPIOLIB_4BIT @@ -162,6 +137,9 @@ config GPIO_SCH The Intel Tunnel Creek processor has 5 GPIOs powered by the core power rail and 9 from suspend power supply. + This driver can also be built as a module. If so, the module + will be called sch-gpio. + config GPIO_VX855 tristate "VIA VX855/VX875 GPIO" depends on MFD_SUPPORT && PCI @@ -224,6 +202,9 @@ config GPIO_PCA953X 16 bits: pca9535, pca9539, pca9555, tca6416 + This driver can also be built as a module. If so, the module + will be called pca953x. + config GPIO_PCA953X_IRQ bool "Interrupt controller support for PCA953x" depends on GPIO_PCA953X=y @@ -315,12 +296,17 @@ config GPIO_ADP5520 This option enables support for on-chip GPIO found on Analog Devices ADP5520 PMICs. + To compile this driver as a module, choose M here: the module will + be called adp5520-gpio. + config GPIO_ADP5588 tristate "ADP5588 I2C GPIO expander" depends on I2C help This option enables support for 18 GPIOs found on Analog Devices ADP5588 GPIO Expanders. + To compile this driver as a module, choose M here: the module will be + called adp5588-gpio. config GPIO_ADP5588_IRQ bool "Interrupt controller support for ADP5588" @@ -412,11 +398,10 @@ config GPIO_MAX7301 GPIO driver for Maxim MAX7301 SPI-based GPIO expander. config GPIO_MCP23S08 - tristate "Microchip MCP23xxx I/O expander" - depends on SPI_MASTER || I2C + tristate "Microchip MCP23Sxx I/O expander" + depends on SPI_MASTER help - SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017 - I/O expanders. + SPI driver for Microchip MCP23S08/MPC23S17 I/O expanders. This provides a GPIO interface supporting inputs and outputs. config GPIO_MC33880 @@ -443,6 +428,9 @@ config GPIO_UCB1400 This enables support for the Philips UCB1400 GPIO pins. The UCB1400 is an AC97 audio codec. + To compile this driver as a module, choose M here: the + module will be called ucb1400_gpio. + comment "MODULbus GPIO expanders:" config GPIO_JANZ_TTL @@ -453,7 +441,7 @@ config GPIO_JANZ_TTL This driver provides support for driving the pins in output mode only. Input mode is not supported. -config GPIO_AB8500 +config AB8500_GPIO bool "ST-Ericsson AB8500 Mixed Signal Circuit gpio functions" depends on AB8500_CORE && BROKEN help diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 72071125139..b605f8ec6fb 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -4,56 +4,47 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG obj-$(CONFIG_GPIOLIB) += gpiolib.o -# Device drivers. Generally keep list sorted alphabetically -obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o - -obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o -obj-$(CONFIG_GPIO_AB8500) += gpio-ab8500.o -obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o -obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o -obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o -obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o -obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o -obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o +obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o +obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o +obj-$(CONFIG_GPIO_BASIC_MMIO_CORE) += basic_mmio_gpio.o +obj-$(CONFIG_GPIO_BASIC_MMIO) += basic_mmio_gpio.o obj-$(CONFIG_GPIO_EXYNOS4) += gpio-exynos4.o -obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o -obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o -obj-$(CONFIG_GPIO_LANGWELL) += gpio-langwell.o -obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o -obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o -obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o -obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o -obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o -obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o -obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o -obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o -obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o -obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o -obj-$(CONFIG_PLAT_NOMADIK) += gpio-nomadik.o -obj-$(CONFIG_ARCH_OMAP) += gpio-omap.o -obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o -obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o -obj-$(CONFIG_GPIO_PCH) += gpio-pch.o -obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o -obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o - obj-$(CONFIG_GPIO_PLAT_SAMSUNG) += gpio-plat-samsung.o obj-$(CONFIG_GPIO_S5PC100) += gpio-s5pc100.o obj-$(CONFIG_GPIO_S5PV210) += gpio-s5pv210.o - -obj-$(CONFIG_GPIO_SCH) += gpio-sch.o -obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o -obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o -obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o -obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o -obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o -obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o -obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o +obj-$(CONFIG_GPIO_LANGWELL) += langwell_gpio.o +obj-$(CONFIG_GPIO_MAX730X) += max730x.o +obj-$(CONFIG_GPIO_MAX7300) += max7300.o +obj-$(CONFIG_GPIO_MAX7301) += max7301.o +obj-$(CONFIG_GPIO_MAX732X) += max732x.o +obj-$(CONFIG_GPIO_MC33880) += mc33880.o +obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o +obj-$(CONFIG_GPIO_74X164) += 74x164.o +obj-$(CONFIG_ARCH_OMAP) += gpio-omap.o +obj-$(CONFIG_GPIO_PCA953X) += pca953x.o +obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o +obj-$(CONFIG_GPIO_PCH) += pch_gpio.o +obj-$(CONFIG_GPIO_PL061) += pl061.o +obj-$(CONFIG_GPIO_STMPE) += stmpe-gpio.o +obj-$(CONFIG_GPIO_TC3589X) += tc3589x-gpio.o +obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o +obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o +obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o +obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o +obj-$(CONFIG_GPIO_CS5535) += cs5535-gpio.o +obj-$(CONFIG_GPIO_BT8XX) += bt8xxgpio.o +obj-$(CONFIG_GPIO_IT8761E) += it8761e_gpio.o +obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o +obj-$(CONFIG_GPIO_WM831X) += wm831x-gpio.o +obj-$(CONFIG_GPIO_WM8350) += wm8350-gpiolib.o +obj-$(CONFIG_GPIO_WM8994) += wm8994-gpio.o +obj-$(CONFIG_GPIO_SCH) += sch_gpio.o obj-$(CONFIG_MACH_U300) += gpio-u300.o -obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o -obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o -obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o -obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o -obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o -obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o -obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o +obj-$(CONFIG_PLAT_NOMADIK) += gpio-nomadik.o +obj-$(CONFIG_GPIO_RDC321X) += rdc321x-gpio.o +obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o +obj-$(CONFIG_GPIO_SX150X) += sx150x.o +obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o +obj-$(CONFIG_GPIO_ML_IOH) += ml_ioh_gpio.o +obj-$(CONFIG_AB8500_GPIO) += ab8500-gpio.o +obj-$(CONFIG_GPIO_TPS65910) += tps65910-gpio.o diff --git a/drivers/gpio/gpio-ab8500.c b/drivers/gpio/ab8500-gpio.c index 970053c89ff..970053c89ff 100644 --- a/drivers/gpio/gpio-ab8500.c +++ b/drivers/gpio/ab8500-gpio.c diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/adp5520-gpio.c index 9f278153700..9f278153700 100644 --- a/drivers/gpio/gpio-adp5520.c +++ b/drivers/gpio/adp5520-gpio.c diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/adp5588-gpio.c index 3525ad91877..3525ad91877 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/adp5588-gpio.c diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/basic_mmio_gpio.c index 231714def4d..8152e9f516b 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/basic_mmio_gpio.c @@ -1,5 +1,5 @@ /* - * Generic driver for memory-mapped GPIO controllers. + * Driver for basic memory-mapped GPIO controllers. * * Copyright 2008 MontaVista Software, Inc. * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com> @@ -404,7 +404,7 @@ int __devinit bgpio_init(struct bgpio_chip *bgc, } EXPORT_SYMBOL_GPL(bgpio_init); -#ifdef CONFIG_GPIO_GENERIC_PLATFORM +#ifdef CONFIG_GPIO_BASIC_MMIO static void __iomem *bgpio_map(struct platform_device *pdev, const char *name, @@ -541,7 +541,7 @@ static void __exit bgpio_platform_exit(void) } module_exit(bgpio_platform_exit); -#endif /* CONFIG_GPIO_GENERIC_PLATFORM */ +#endif /* CONFIG_GPIO_BASIC_MMIO */ MODULE_DESCRIPTION("Driver for basic memory-mapped GPIO controllers"); MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>"); diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/bt8xxgpio.c index aa4f09ad3ce..aa4f09ad3ce 100644 --- a/drivers/gpio/gpio-bt8xx.c +++ b/drivers/gpio/bt8xxgpio.c diff --git a/drivers/gpio/gpio-cs5535.c b/drivers/gpio/cs5535-gpio.c index 6e16cba56ad..6e16cba56ad 100644 --- a/drivers/gpio/gpio-cs5535.c +++ b/drivers/gpio/cs5535-gpio.c diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c deleted file mode 100644 index 038f5eb8b13..00000000000 --- a/drivers/gpio/gpio-da9052.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * GPIO Driver for Dialog DA9052 PMICs. - * - * Copyright(c) 2011 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/module.h> -#include <linux/fs.h> -#include <linux/uaccess.h> -#include <linux/platform_device.h> -#include <linux/gpio.h> -#include <linux/syscalls.h> -#include <linux/seq_file.h> - -#include <linux/mfd/da9052/da9052.h> -#include <linux/mfd/da9052/reg.h> -#include <linux/mfd/da9052/pdata.h> -#include <linux/mfd/da9052/gpio.h> - -#define DA9052_INPUT 1 -#define DA9052_OUTPUT_OPENDRAIN 2 -#define DA9052_OUTPUT_PUSHPULL 3 - -#define DA9052_SUPPLY_VDD_IO1 0 - -#define DA9052_DEBOUNCING_OFF 0 -#define DA9052_DEBOUNCING_ON 1 - -#define DA9052_OUTPUT_LOWLEVEL 0 - -#define DA9052_ACTIVE_LOW 0 -#define DA9052_ACTIVE_HIGH 1 - -#define DA9052_GPIO_MAX_PORTS_PER_REGISTER 8 -#define DA9052_GPIO_SHIFT_COUNT(no) (no%8) -#define DA9052_GPIO_MASK_UPPER_NIBBLE 0xF0 -#define DA9052_GPIO_MASK_LOWER_NIBBLE 0x0F -#define DA9052_GPIO_NIBBLE_SHIFT 4 - -struct da9052_gpio { - struct da9052 *da9052; - struct gpio_chip gp; -}; - -static inline struct da9052_gpio *to_da9052_gpio(struct gpio_chip *chip) -{ - return container_of(chip, struct da9052_gpio, gp); -} - -static unsigned char da9052_gpio_port_odd(unsigned offset) -{ - return offset % 2; -} - -static int da9052_gpio_get(struct gpio_chip *gc, unsigned offset) -{ - struct da9052_gpio *gpio = to_da9052_gpio(gc); - int da9052_port_direction = 0; - int ret; - - ret = da9052_reg_read(gpio->da9052, - DA9052_GPIO_0_1_REG + (offset >> 1)); - if (ret < 0) - return ret; - - if (da9052_gpio_port_odd(offset)) { - da9052_port_direction = ret & DA9052_GPIO_ODD_PORT_PIN; - da9052_port_direction >>= 4; - } else { - da9052_port_direction = ret & DA9052_GPIO_EVEN_PORT_PIN; - } - - switch (da9052_port_direction) { - case DA9052_INPUT: - if (offset < DA9052_GPIO_MAX_PORTS_PER_REGISTER) - ret = da9052_reg_read(gpio->da9052, - DA9052_STATUS_C_REG); - else - ret = da9052_reg_read(gpio->da9052, - DA9052_STATUS_D_REG); - if (ret < 0) - return ret; - if (ret & (1 << DA9052_GPIO_SHIFT_COUNT(offset))) - return 1; - else - return 0; - case DA9052_OUTPUT_PUSHPULL: - if (da9052_gpio_port_odd(offset)) - return ret & DA9052_GPIO_ODD_PORT_MODE; - else - return ret & DA9052_GPIO_EVEN_PORT_MODE; - default: - return -EINVAL; - } -} - -static void da9052_gpio_set(struct gpio_chip *gc, unsigned offset, int value) -{ - struct da9052_gpio *gpio = to_da9052_gpio(gc); - unsigned char register_value = 0; - int ret; - - if (da9052_gpio_port_odd(offset)) { - if (value) { - register_value = DA9052_GPIO_ODD_PORT_MODE; - ret = da9052_reg_update(gpio->da9052, (offset >> 1) + - DA9052_GPIO_0_1_REG, - DA9052_GPIO_ODD_PORT_MODE, - register_value); - if (ret != 0) - dev_err(gpio->da9052->dev, - "Failed to updated gpio odd reg,%d", - ret); - } - } else { - if (value) { - register_value = DA9052_GPIO_EVEN_PORT_MODE; - ret = da9052_reg_update(gpio->da9052, (offset >> 1) + - DA9052_GPIO_0_1_REG, - DA9052_GPIO_EVEN_PORT_MODE, - register_value); - if (ret != 0) - dev_err(gpio->da9052->dev, - "Failed to updated gpio even reg,%d", - ret); - } - } -} - -static int da9052_gpio_direction_input(struct gpio_chip *gc, unsigned offset) -{ - struct da9052_gpio *gpio = to_da9052_gpio(gc); - unsigned char register_value; - int ret; - - /* Format: function - 2 bits type - 1 bit mode - 1 bit */ - register_value = DA9052_INPUT | DA9052_ACTIVE_LOW << 2 | - DA9052_DEBOUNCING_ON << 3; - - if (da9052_gpio_port_odd(offset)) - ret = da9052_reg_update(gpio->da9052, (offset >> 1) + - DA9052_GPIO_0_1_REG, - DA9052_GPIO_MASK_UPPER_NIBBLE, - (register_value << - DA9052_GPIO_NIBBLE_SHIFT)); - else - ret = da9052_reg_update(gpio->da9052, (offset >> 1) + - DA9052_GPIO_0_1_REG, - DA9052_GPIO_MASK_LOWER_NIBBLE, - register_value); - - return ret; -} - -static int da9052_gpio_direction_output(struct gpio_chip *gc, - unsigned offset, int value) -{ - struct da9052_gpio *gpio = to_da9052_gpio(gc); - unsigned char register_value; - int ret; - - /* Format: Function - 2 bits Type - 1 bit Mode - 1 bit */ - register_value = DA9052_OUTPUT_PUSHPULL | DA9052_SUPPLY_VDD_IO1 << 2 | - value << 3; - - if (da9052_gpio_port_odd(offset)) - ret = da9052_reg_update(gpio->da9052, (offset >> 1) + - DA9052_GPIO_0_1_REG, - DA9052_GPIO_MASK_UPPER_NIBBLE, - (register_value << - DA9052_GPIO_NIBBLE_SHIFT)); - else - ret = da9052_reg_update(gpio->da9052, (offset >> 1) + - DA9052_GPIO_0_1_REG, - DA9052_GPIO_MASK_LOWER_NIBBLE, - register_value); - - return ret; -} - -static int da9052_gpio_to_irq(struct gpio_chip *gc, u32 offset) -{ - struct da9052_gpio *gpio = to_da9052_gpio(gc); - struct da9052 *da9052 = gpio->da9052; - - return da9052->irq_base + DA9052_IRQ_GPI0 + offset; -} - -static struct gpio_chip reference_gp __devinitdata = { - .label = "da9052-gpio", - .owner = THIS_MODULE, - .get = da9052_gpio_get, - .set = da9052_gpio_set, - .direction_input = da9052_gpio_direction_input, - .direction_output = da9052_gpio_direction_output, - .to_irq = da9052_gpio_to_irq, - .can_sleep = 1; - .ngpio = 16; - .base = -1; -}; - -static int __devinit da9052_gpio_probe(struct platform_device *pdev) -{ - struct da9052_gpio *gpio; - struct da9052_pdata *pdata; - int ret; - - gpio = kzalloc(sizeof(*gpio), GFP_KERNEL); - if (gpio == NULL) - return -ENOMEM; - - gpio->da9052 = dev_get_drvdata(pdev->dev.parent); - pdata = gpio->da9052->dev->platform_data; - - gpio->gp = reference_gp; - if (pdata && pdata->gpio_base) - gpio->gp.base = pdata->gpio_base; - - ret = gpiochip_add(&gpio->gp); - if (ret < 0) { - dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); - goto err_mem; - } - - platform_set_drvdata(pdev, gpio); - - return 0; - -err_mem: - kfree(gpio); - return ret; -} - -static int __devexit da9052_gpio_remove(struct platform_device *pdev) -{ - struct da9052_gpio *gpio = platform_get_drvdata(pdev); - int ret; - - ret = gpiochip_remove(&gpio->gp); - if (ret == 0) - kfree(gpio); - - return ret; -} - -static struct platform_driver da9052_gpio_driver = { - .probe = da9052_gpio_probe, - .remove = __devexit_p(da9052_gpio_remove), - .driver = { - .name = "da9052-gpio", - .owner = THIS_MODULE, - }, -}; - -static int __init da9052_gpio_init(void) -{ - return platform_driver_register(&da9052_gpio_driver); -} -module_init(da9052_gpio_init); - -static void __exit da9052_gpio_exit(void) -{ - return platform_driver_unregister(&da9052_gpio_driver); -} -module_exit(da9052_gpio_exit); - -MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); -MODULE_DESCRIPTION("DA9052 GPIO Device Driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:da9052-gpio"); diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c deleted file mode 100644 index 3bfd3417ab1..00000000000 --- a/drivers/gpio/gpio-ep93xx.c +++ /dev/null @@ -1,405 +0,0 @@ -/* - * Generic EP93xx GPIO handling - * - * Copyright (c) 2008 Ryan Mallon <ryan@bluewatersys.com> - * Copyright (c) 2011 H Hartley Sweeten <hsweeten@visionengravers.com> - * - * Based on code originally from: - * linux/arch/arm/mach-ep93xx/core.c - * - * 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. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/gpio.h> -#include <linux/irq.h> -#include <linux/slab.h> -#include <linux/basic_mmio_gpio.h> - -#include <mach/hardware.h> - -struct ep93xx_gpio { - void __iomem *mmio_base; - struct bgpio_chip bgc[8]; -}; - -/************************************************************************* - * Interrupt handling for EP93xx on-chip GPIOs - *************************************************************************/ -static unsigned char gpio_int_unmasked[3]; -static unsigned char gpio_int_enabled[3]; -static unsigned char gpio_int_type1[3]; -static unsigned char gpio_int_type2[3]; -static unsigned char gpio_int_debounce[3]; - -/* Port ordering is: A B F */ -static const u8 int_type1_register_offset[3] = { 0x90, 0xac, 0x4c }; -static const u8 int_type2_register_offset[3] = { 0x94, 0xb0, 0x50 }; -static const u8 eoi_register_offset[3] = { 0x98, 0xb4, 0x54 }; -static const u8 int_en_register_offset[3] = { 0x9c, 0xb8, 0x58 }; -static const u8 int_debounce_register_offset[3] = { 0xa8, 0xc4, 0x64 }; - -static void ep93xx_gpio_update_int_params(unsigned port) -{ - BUG_ON(port > 2); - - __raw_writeb(0, EP93XX_GPIO_REG(int_en_register_offset[port])); - - __raw_writeb(gpio_int_type2[port], - EP93XX_GPIO_REG(int_type2_register_offset[port])); - - __raw_writeb(gpio_int_type1[port], - EP93XX_GPIO_REG(int_type1_register_offset[port])); - - __raw_writeb(gpio_int_unmasked[port] & gpio_int_enabled[port], - EP93XX_GPIO_REG(int_en_register_offset[port])); -} - -static inline void ep93xx_gpio_int_mask(unsigned line) -{ - gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7)); -} - -static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable) -{ - int line = irq_to_gpio(irq); - int port = line >> 3; - int port_mask = 1 << (line & 7); - - if (enable) - gpio_int_debounce[port] |= port_mask; - else - gpio_int_debounce[port] &= ~port_mask; - - __raw_writeb(gpio_int_debounce[port], - EP93XX_GPIO_REG(int_debounce_register_offset[port])); -} - -static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - unsigned char status; - int i; - - status = __raw_readb(EP93XX_GPIO_A_INT_STATUS); - for (i = 0; i < 8; i++) { - if (status & (1 << i)) { - int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i; - generic_handle_irq(gpio_irq); - } - } - - status = __raw_readb(EP93XX_GPIO_B_INT_STATUS); - for (i = 0; i < 8; i++) { - if (status & (1 << i)) { - int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i; - generic_handle_irq(gpio_irq); - } - } -} - -static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - /* - * map discontiguous hw irq range to continuous sw irq range: - * - * IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..7}) - */ - int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */ - int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx; - - generic_handle_irq(gpio_irq); -} - -static void ep93xx_gpio_irq_ack(struct irq_data *d) -{ - int line = irq_to_gpio(d->irq); - int port = line >> 3; - int port_mask = 1 << (line & 7); - - if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) { - gpio_int_type2[port] ^= port_mask; /* switch edge direction */ - ep93xx_gpio_update_int_params(port); - } - - __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); -} - -static void ep93xx_gpio_irq_mask_ack(struct irq_data *d) -{ - int line = irq_to_gpio(d->irq); - int port = line >> 3; - int port_mask = 1 << (line & 7); - - if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) - gpio_int_type2[port] ^= port_mask; /* switch edge direction */ - - gpio_int_unmasked[port] &= ~port_mask; - ep93xx_gpio_update_int_params(port); - - __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); -} - -static void ep93xx_gpio_irq_mask(struct irq_data *d) -{ - int line = irq_to_gpio(d->irq); - int port = line >> 3; - - gpio_int_unmasked[port] &= ~(1 << (line & 7)); - ep93xx_gpio_update_int_params(port); -} - -static void ep93xx_gpio_irq_unmask(struct irq_data *d) -{ - int line = irq_to_gpio(d->irq); - int port = line >> 3; - - gpio_int_unmasked[port] |= 1 << (line & 7); - ep93xx_gpio_update_int_params(port); -} - -/* - * gpio_int_type1 controls whether the interrupt is level (0) or - * edge (1) triggered, while gpio_int_type2 controls whether it - * triggers on low/falling (0) or high/rising (1). - */ -static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type) -{ - const int gpio = irq_to_gpio(d->irq); - const int port = gpio >> 3; - const int port_mask = 1 << (gpio & 7); - irq_flow_handler_t handler; - - gpio_direction_input(gpio); - - switch (type) { - case IRQ_TYPE_EDGE_RISING: - gpio_int_type1[port] |= port_mask; - gpio_int_type2[port] |= port_mask; - handler = handle_edge_irq; - break; - case IRQ_TYPE_EDGE_FALLING: - gpio_int_type1[port] |= port_mask; - gpio_int_type2[port] &= ~port_mask; - handler = handle_edge_irq; - break; - case IRQ_TYPE_LEVEL_HIGH: - gpio_int_type1[port] &= ~port_mask; - gpio_int_type2[port] |= port_mask; - handler = handle_level_irq; - break; - case IRQ_TYPE_LEVEL_LOW: - gpio_int_type1[port] &= ~port_mask; - gpio_int_type2[port] &= ~port_mask; - handler = handle_level_irq; - break; - case IRQ_TYPE_EDGE_BOTH: - gpio_int_type1[port] |= port_mask; - /* set initial polarity based on current input level */ - if (gpio_get_value(gpio)) - gpio_int_type2[port] &= ~port_mask; /* falling */ - else - gpio_int_type2[port] |= port_mask; /* rising */ - handler = handle_edge_irq; - break; - default: - pr_err("failed to set irq type %d for gpio %d\n", type, gpio); - return -EINVAL; - } - - __irq_set_handler_locked(d->irq, handler); - - gpio_int_enabled[port] |= port_mask; - - ep93xx_gpio_update_int_params(port); - - return 0; -} - -static struct irq_chip ep93xx_gpio_irq_chip = { - .name = "GPIO", - .irq_ack = ep93xx_gpio_irq_ack, - .irq_mask_ack = ep93xx_gpio_irq_mask_ack, - .irq_mask = ep93xx_gpio_irq_mask, - .irq_unmask = ep93xx_gpio_irq_unmask, - .irq_set_type = ep93xx_gpio_irq_type, -}; - -static void ep93xx_gpio_init_irq(void) -{ - int gpio_irq; - - for (gpio_irq = gpio_to_irq(0); - gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) { - irq_set_chip_and_handler(gpio_irq, &ep93xx_gpio_irq_chip, - handle_level_irq); - set_irq_flags(gpio_irq, IRQF_VALID); - } - - irq_set_chained_handler(IRQ_EP93XX_GPIO_AB, - ep93xx_gpio_ab_irq_handler); - irq_set_chained_handler(IRQ_EP93XX_GPIO0MUX, - ep93xx_gpio_f_irq_handler); - irq_set_chained_handler(IRQ_EP93XX_GPIO1MUX, - ep93xx_gpio_f_irq_handler); - irq_set_chained_handler(IRQ_EP93XX_GPIO2MUX, - ep93xx_gpio_f_irq_handler); - irq_set_chained_handler(IRQ_EP93XX_GPIO3MUX, - ep93xx_gpio_f_irq_handler); - irq_set_chained_handler(IRQ_EP93XX_GPIO4MUX, - ep93xx_gpio_f_irq_handler); - irq_set_chained_handler(IRQ_EP93XX_GPIO5MUX, - ep93xx_gpio_f_irq_handler); - irq_set_chained_handler(IRQ_EP93XX_GPIO6MUX, - ep93xx_gpio_f_irq_handler); - irq_set_chained_handler(IRQ_EP93XX_GPIO7MUX, - ep93xx_gpio_f_irq_handler); -} - - -/************************************************************************* - * gpiolib interface for EP93xx on-chip GPIOs - *************************************************************************/ -struct ep93xx_gpio_bank { - const char *label; - int data; - int dir; - int base; - bool has_debounce; -}; - -#define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _debounce) \ - { \ - .label = _label, \ - .data = _data, \ - .dir = _dir, \ - .base = _base, \ - .has_debounce = _debounce, \ - } - -static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = { - EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true), - EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true), - EP93XX_GPIO_BANK("C", 0x08, 0x18, 40, false), - EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24, false), - EP93XX_GPIO_BANK("E", 0x20, 0x24, 32, false), - EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, true), - EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48, false), - EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false), -}; - -static int ep93xx_gpio_set_debounce(struct gpio_chip *chip, - unsigned offset, unsigned debounce) -{ - int gpio = chip->base + offset; - int irq = gpio_to_irq(gpio); - - if (irq < 0) - return -EINVAL; - - ep93xx_gpio_int_debounce(irq, debounce ? true : false); - - return 0; -} - -static int ep93xx_gpio_add_bank(struct bgpio_chip *bgc, struct device *dev, - void __iomem *mmio_base, struct ep93xx_gpio_bank *bank) -{ - void __iomem *data = mmio_base + bank->data; - void __iomem *dir = mmio_base + bank->dir; - int err; - - err = bgpio_init(bgc, dev, 1, data, NULL, NULL, dir, NULL, false); - if (err) - return err; - - bgc->gc.label = bank->label; - bgc->gc.base = bank->base; - - if (bank->has_debounce) - bgc->gc.set_debounce = ep93xx_gpio_set_debounce; - - return gpiochip_add(&bgc->gc); -} - -static int __devinit ep93xx_gpio_probe(struct platform_device *pdev) -{ - struct ep93xx_gpio *ep93xx_gpio; - struct resource *res; - void __iomem *mmio; - int i; - int ret; - - ep93xx_gpio = kzalloc(sizeof(*ep93xx_gpio), GFP_KERNEL); - if (!ep93xx_gpio) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENXIO; - goto exit_free; - } - - if (!request_mem_region(res->start, resource_size(res), pdev->name)) { - ret = -EBUSY; - goto exit_free; - } - - mmio = ioremap(res->start, resource_size(res)); - if (!mmio) { - ret = -ENXIO; - goto exit_release; - } - ep93xx_gpio->mmio_base = mmio; - - /* Default all ports to GPIO */ - ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_KEYS | - EP93XX_SYSCON_DEVCFG_GONK | - EP93XX_SYSCON_DEVCFG_EONIDE | - EP93XX_SYSCON_DEVCFG_GONIDE | - EP93XX_SYSCON_DEVCFG_HONIDE); - - for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) { - struct bgpio_chip *bgc = &ep93xx_gpio->bgc[i]; - struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i]; - - if (ep93xx_gpio_add_bank(bgc, &pdev->dev, mmio, bank)) - dev_warn(&pdev->dev, "Unable to add gpio bank %s\n", - bank->label); - } - - ep93xx_gpio_init_irq(); - - return 0; - -exit_release: - release_mem_region(res->start, resource_size(res)); -exit_free: - kfree(ep93xx_gpio); - dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, ret); - return ret; -} - -static struct platform_driver ep93xx_gpio_driver = { - .driver = { - .name = "gpio-ep93xx", - .owner = THIS_MODULE, - }, - .probe = ep93xx_gpio_probe, -}; - -static int __init ep93xx_gpio_init(void) -{ - return platform_driver_register(&ep93xx_gpio_driver); -} -postcore_initcall(ep93xx_gpio_init); - -MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com> " - "H Hartley Sweeten <hsweeten@visionengravers.com>"); -MODULE_DESCRIPTION("EP93XX GPIO driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-exynos4.c b/drivers/gpio/gpio-exynos4.c index d24b337cf1a..9029835112e 100644 --- a/drivers/gpio/gpio-exynos4.c +++ b/drivers/gpio/gpio-exynos4.c @@ -1,9 +1,10 @@ -/* - * EXYNOS4 - GPIOlib support +/* linux/arch/arm/mach-exynos4/gpiolib.c * * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * + * EXYNOS4 - GPIOlib support + * * 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. diff --git a/drivers/gpio/gpio-mpc5200.c b/drivers/gpio/gpio-mpc5200.c deleted file mode 100644 index 52d3ed20810..00000000000 --- a/drivers/gpio/gpio-mpc5200.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - * MPC52xx gpio driver - * - * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/of.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/of_gpio.h> -#include <linux/io.h> -#include <linux/of_platform.h> - -#include <asm/gpio.h> -#include <asm/mpc52xx.h> -#include <sysdev/fsl_soc.h> - -static DEFINE_SPINLOCK(gpio_lock); - -struct mpc52xx_gpiochip { - struct of_mm_gpio_chip mmchip; - unsigned int shadow_dvo; - unsigned int shadow_gpioe; - unsigned int shadow_ddr; -}; - -/* - * GPIO LIB API implementation for wakeup GPIOs. - * - * There's a maximum of 8 wakeup GPIOs. Which of these are available - * for use depends on your board setup. - * - * 0 -> GPIO_WKUP_7 - * 1 -> GPIO_WKUP_6 - * 2 -> PSC6_1 - * 3 -> PSC6_0 - * 4 -> ETH_17 - * 5 -> PSC3_9 - * 6 -> PSC2_4 - * 7 -> PSC1_4 - * - */ -static int mpc52xx_wkup_gpio_get(struct gpio_chip *gc, unsigned int gpio) -{ - struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs; - unsigned int ret; - - ret = (in_8(®s->wkup_ival) >> (7 - gpio)) & 1; - - pr_debug("%s: gpio: %d ret: %d\n", __func__, gpio, ret); - - return ret; -} - -static inline void -__mpc52xx_wkup_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) -{ - struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct mpc52xx_gpiochip *chip = container_of(mm_gc, - struct mpc52xx_gpiochip, mmchip); - struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs; - - if (val) - chip->shadow_dvo |= 1 << (7 - gpio); - else - chip->shadow_dvo &= ~(1 << (7 - gpio)); - - out_8(®s->wkup_dvo, chip->shadow_dvo); -} - -static void -mpc52xx_wkup_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) -{ - unsigned long flags; - - spin_lock_irqsave(&gpio_lock, flags); - - __mpc52xx_wkup_gpio_set(gc, gpio, val); - - spin_unlock_irqrestore(&gpio_lock, flags); - - pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val); -} - -static int mpc52xx_wkup_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) -{ - struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct mpc52xx_gpiochip *chip = container_of(mm_gc, - struct mpc52xx_gpiochip, mmchip); - struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs; - unsigned long flags; - - spin_lock_irqsave(&gpio_lock, flags); - - /* set the direction */ - chip->shadow_ddr &= ~(1 << (7 - gpio)); - out_8(®s->wkup_ddr, chip->shadow_ddr); - - /* and enable the pin */ - chip->shadow_gpioe |= 1 << (7 - gpio); - out_8(®s->wkup_gpioe, chip->shadow_gpioe); - - spin_unlock_irqrestore(&gpio_lock, flags); - - return 0; -} - -static int -mpc52xx_wkup_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) -{ - struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs; - struct mpc52xx_gpiochip *chip = container_of(mm_gc, - struct mpc52xx_gpiochip, mmchip); - unsigned long flags; - - spin_lock_irqsave(&gpio_lock, flags); - - __mpc52xx_wkup_gpio_set(gc, gpio, val); - - /* Then set direction */ - chip->shadow_ddr |= 1 << (7 - gpio); - out_8(®s->wkup_ddr, chip->shadow_ddr); - - /* Finally enable the pin */ - chip->shadow_gpioe |= 1 << (7 - gpio); - out_8(®s->wkup_gpioe, chip->shadow_gpioe); - - spin_unlock_irqrestore(&gpio_lock, flags); - - pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val); - - return 0; -} - -static int __devinit mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev) -{ - struct mpc52xx_gpiochip *chip; - struct mpc52xx_gpio_wkup __iomem *regs; - struct gpio_chip *gc; - int ret; - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - gc = &chip->mmchip.gc; - - gc->ngpio = 8; - gc->direction_input = mpc52xx_wkup_gpio_dir_in; - gc->direction_output = mpc52xx_wkup_gpio_dir_out; - gc->get = mpc52xx_wkup_gpio_get; - gc->set = mpc52xx_wkup_gpio_set; - - ret = of_mm_gpiochip_add(ofdev->dev.of_node, &chip->mmchip); - if (ret) - return ret; - - regs = chip->mmchip.regs; - chip->shadow_gpioe = in_8(®s->wkup_gpioe); - chip->shadow_ddr = in_8(®s->wkup_ddr); - chip->shadow_dvo = in_8(®s->wkup_dvo); - - return 0; -} - -static int mpc52xx_gpiochip_remove(struct platform_device *ofdev) -{ - return -EBUSY; -} - -static const struct of_device_id mpc52xx_wkup_gpiochip_match[] = { - { .compatible = "fsl,mpc5200-gpio-wkup", }, - {} -}; - -static struct platform_driver mpc52xx_wkup_gpiochip_driver = { - .driver = { - .name = "mpc5200-gpio-wkup", - .owner = THIS_MODULE, - .of_match_table = mpc52xx_wkup_gpiochip_match, - }, - .probe = mpc52xx_wkup_gpiochip_probe, - .remove = mpc52xx_gpiochip_remove, -}; - -/* - * GPIO LIB API implementation for simple GPIOs - * - * There's a maximum of 32 simple GPIOs. Which of these are available - * for use depends on your board setup. - * The numbering reflects the bit numbering in the port registers: - * - * 0..1 > reserved - * 2..3 > IRDA - * 4..7 > ETHR - * 8..11 > reserved - * 12..15 > USB - * 16..17 > reserved - * 18..23 > PSC3 - * 24..27 > PSC2 - * 28..31 > PSC1 - */ -static int mpc52xx_simple_gpio_get(struct gpio_chip *gc, unsigned int gpio) -{ - struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct mpc52xx_gpio __iomem *regs = mm_gc->regs; - unsigned int ret; - - ret = (in_be32(®s->simple_ival) >> (31 - gpio)) & 1; - - return ret; -} - -static inline void -__mpc52xx_simple_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) -{ - struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct mpc52xx_gpiochip *chip = container_of(mm_gc, - struct mpc52xx_gpiochip, mmchip); - struct mpc52xx_gpio __iomem *regs = mm_gc->regs; - - if (val) - chip->shadow_dvo |= 1 << (31 - gpio); - else - chip->shadow_dvo &= ~(1 << (31 - gpio)); - out_be32(®s->simple_dvo, chip->shadow_dvo); -} - -static void -mpc52xx_simple_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) -{ - unsigned long flags; - - spin_lock_irqsave(&gpio_lock, flags); - - __mpc52xx_simple_gpio_set(gc, gpio, val); - - spin_unlock_irqrestore(&gpio_lock, flags); - - pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val); -} - -static int mpc52xx_simple_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) -{ - struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct mpc52xx_gpiochip *chip = container_of(mm_gc, - struct mpc52xx_gpiochip, mmchip); - struct mpc52xx_gpio __iomem *regs = mm_gc->regs; - unsigned long flags; - - spin_lock_irqsave(&gpio_lock, flags); - - /* set the direction */ - chip->shadow_ddr &= ~(1 << (31 - gpio)); - out_be32(®s->simple_ddr, chip->shadow_ddr); - - /* and enable the pin */ - chip->shadow_gpioe |= 1 << (31 - gpio); - out_be32(®s->simple_gpioe, chip->shadow_gpioe); - - spin_unlock_irqrestore(&gpio_lock, flags); - - return 0; -} - -static int -mpc52xx_simple_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) -{ - struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct mpc52xx_gpiochip *chip = container_of(mm_gc, - struct mpc52xx_gpiochip, mmchip); - struct mpc52xx_gpio __iomem *regs = mm_gc->regs; - unsigned long flags; - - spin_lock_irqsave(&gpio_lock, flags); - - /* First set initial value */ - __mpc52xx_simple_gpio_set(gc, gpio, val); - - /* Then set direction */ - chip->shadow_ddr |= 1 << (31 - gpio); - out_be32(®s->simple_ddr, chip->shadow_ddr); - - /* Finally enable the pin */ - chip->shadow_gpioe |= 1 << (31 - gpio); - out_be32(®s->simple_gpioe, chip->shadow_gpioe); - - spin_unlock_irqrestore(&gpio_lock, flags); - - pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val); - - return 0; -} - -static int __devinit mpc52xx_simple_gpiochip_probe(struct platform_device *ofdev) -{ - struct mpc52xx_gpiochip *chip; - struct gpio_chip *gc; - struct mpc52xx_gpio __iomem *regs; - int ret; - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - gc = &chip->mmchip.gc; - - gc->ngpio = 32; - gc->direction_input = mpc52xx_simple_gpio_dir_in; - gc->direction_output = mpc52xx_simple_gpio_dir_out; - gc->get = mpc52xx_simple_gpio_get; - gc->set = mpc52xx_simple_gpio_set; - - ret = of_mm_gpiochip_add(ofdev->dev.of_node, &chip->mmchip); - if (ret) - return ret; - - regs = chip->mmchip.regs; - chip->shadow_gpioe = in_be32(®s->simple_gpioe); - chip->shadow_ddr = in_be32(®s->simple_ddr); - chip->shadow_dvo = in_be32(®s->simple_dvo); - - return 0; -} - -static const struct of_device_id mpc52xx_simple_gpiochip_match[] = { - { .compatible = "fsl,mpc5200-gpio", }, - {} -}; - -static struct platform_driver mpc52xx_simple_gpiochip_driver = { - .driver = { - .name = "mpc5200-gpio", - .owner = THIS_MODULE, - .of_match_table = mpc52xx_simple_gpiochip_match, - }, - .probe = mpc52xx_simple_gpiochip_probe, - .remove = mpc52xx_gpiochip_remove, -}; - -static int __init mpc52xx_gpio_init(void) -{ - if (platform_driver_register(&mpc52xx_wkup_gpiochip_driver)) - printk(KERN_ERR "Unable to register wakeup GPIO driver\n"); - - if (platform_driver_register(&mpc52xx_simple_gpiochip_driver)) - printk(KERN_ERR "Unable to register simple GPIO driver\n"); - - return 0; -} - - -/* Make sure we get initialised before anyone else tries to use us */ -subsys_initcall(mpc52xx_gpio_init); - -/* No exit call at the moment as we cannot unregister of gpio chips */ - -MODULE_DESCRIPTION("Freescale MPC52xx gpio driver"); -MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de"); -MODULE_LICENSE("GPL v2"); - diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c deleted file mode 100644 index 89fda58db90..00000000000 --- a/drivers/gpio/gpio-mxc.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de> - * Copyright 2008 Juergen Beisert, kernel@pengutronix.de - * - * Based on code from Freescale, - * Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/gpio.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/basic_mmio_gpio.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <asm-generic/bug.h> - -enum mxc_gpio_hwtype { - IMX1_GPIO, /* runs on i.mx1 */ - IMX21_GPIO, /* runs on i.mx21 and i.mx27 */ - IMX31_GPIO, /* runs on all other i.mx */ -}; - -/* device type dependent stuff */ -struct mxc_gpio_hwdata { - unsigned dr_reg; - unsigned gdir_reg; - unsigned psr_reg; - unsigned icr1_reg; - unsigned icr2_reg; - unsigned imr_reg; - unsigned isr_reg; - unsigned low_level; - unsigned high_level; - unsigned rise_edge; - unsigned fall_edge; -}; - -struct mxc_gpio_port { - struct list_head node; - void __iomem *base; - int irq; - int irq_high; - int virtual_irq_start; - struct bgpio_chip bgc; - u32 both_edges; -}; - -static struct mxc_gpio_hwdata imx1_imx21_gpio_hwdata = { - .dr_reg = 0x1c, - .gdir_reg = 0x00, - .psr_reg = 0x24, - .icr1_reg = 0x28, - .icr2_reg = 0x2c, - .imr_reg = 0x30, - .isr_reg = 0x34, - .low_level = 0x03, - .high_level = 0x02, - .rise_edge = 0x00, - .fall_edge = 0x01, -}; - -static struct mxc_gpio_hwdata imx31_gpio_hwdata = { - .dr_reg = 0x00, - .gdir_reg = 0x04, - .psr_reg = 0x08, - .icr1_reg = 0x0c, - .icr2_reg = 0x10, - .imr_reg = 0x14, - .isr_reg = 0x18, - .low_level = 0x00, - .high_level = 0x01, - .rise_edge = 0x02, - .fall_edge = 0x03, -}; - -static enum mxc_gpio_hwtype mxc_gpio_hwtype; -static struct mxc_gpio_hwdata *mxc_gpio_hwdata; - -#define GPIO_DR (mxc_gpio_hwdata->dr_reg) -#define GPIO_GDIR (mxc_gpio_hwdata->gdir_reg) -#define GPIO_PSR (mxc_gpio_hwdata->psr_reg) -#define GPIO_ICR1 (mxc_gpio_hwdata->icr1_reg) -#define GPIO_ICR2 (mxc_gpio_hwdata->icr2_reg) -#define GPIO_IMR (mxc_gpio_hwdata->imr_reg) -#define GPIO_ISR (mxc_gpio_hwdata->isr_reg) - -#define GPIO_INT_LOW_LEV (mxc_gpio_hwdata->low_level) -#define GPIO_INT_HIGH_LEV (mxc_gpio_hwdata->high_level) -#define GPIO_INT_RISE_EDGE (mxc_gpio_hwdata->rise_edge) -#define GPIO_INT_FALL_EDGE (mxc_gpio_hwdata->fall_edge) -#define GPIO_INT_NONE 0x4 - -static struct platform_device_id mxc_gpio_devtype[] = { - { - .name = "imx1-gpio", - .driver_data = IMX1_GPIO, - }, { - .name = "imx21-gpio", - .driver_data = IMX21_GPIO, - }, { - .name = "imx31-gpio", - .driver_data = IMX31_GPIO, - }, { - /* sentinel */ - } -}; - -static const struct of_device_id mxc_gpio_dt_ids[] = { - { .compatible = "fsl,imx1-gpio", .data = &mxc_gpio_devtype[IMX1_GPIO], }, - { .compatible = "fsl,imx21-gpio", .data = &mxc_gpio_devtype[IMX21_GPIO], }, - { .compatible = "fsl,imx31-gpio", .data = &mxc_gpio_devtype[IMX31_GPIO], }, - { /* sentinel */ } -}; - -/* - * MX2 has one interrupt *for all* gpio ports. The list is used - * to save the references to all ports, so that mx2_gpio_irq_handler - * can walk through all interrupt status registers. - */ -static LIST_HEAD(mxc_gpio_ports); - -/* Note: This driver assumes 32 GPIOs are handled in one register */ - -static int gpio_set_irq_type(struct irq_data *d, u32 type) -{ - u32 gpio = irq_to_gpio(d->irq); - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - struct mxc_gpio_port *port = gc->private; - u32 bit, val; - int edge; - void __iomem *reg = port->base; - - port->both_edges &= ~(1 << (gpio & 31)); - switch (type) { - case IRQ_TYPE_EDGE_RISING: - edge = GPIO_INT_RISE_EDGE; - break; - case IRQ_TYPE_EDGE_FALLING: - edge = GPIO_INT_FALL_EDGE; - break; - case IRQ_TYPE_EDGE_BOTH: - val = gpio_get_value(gpio); - if (val) { - edge = GPIO_INT_LOW_LEV; - pr_debug("mxc: set GPIO %d to low trigger\n", gpio); - } else { - edge = GPIO_INT_HIGH_LEV; - pr_debug("mxc: set GPIO %d to high trigger\n", gpio); - } - port->both_edges |= 1 << (gpio & 31); - break; - case IRQ_TYPE_LEVEL_LOW: - edge = GPIO_INT_LOW_LEV; - break; - case IRQ_TYPE_LEVEL_HIGH: - edge = GPIO_INT_HIGH_LEV; - break; - default: - return -EINVAL; - } - - reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ - bit = gpio & 0xf; - val = readl(reg) & ~(0x3 << (bit << 1)); - writel(val | (edge << (bit << 1)), reg); - writel(1 << (gpio & 0x1f), port->base + GPIO_ISR); - - return 0; -} - -static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) -{ - void __iomem *reg = port->base; - u32 bit, val; - int edge; - - reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ - bit = gpio & 0xf; - val = readl(reg); - edge = (val >> (bit << 1)) & 3; - val &= ~(0x3 << (bit << 1)); - if (edge == GPIO_INT_HIGH_LEV) { - edge = GPIO_INT_LOW_LEV; - pr_debug("mxc: switch GPIO %d to low trigger\n", gpio); - } else if (edge == GPIO_INT_LOW_LEV) { - edge = GPIO_INT_HIGH_LEV; - pr_debug("mxc: switch GPIO %d to high trigger\n", gpio); - } else { - pr_err("mxc: invalid configuration for GPIO %d: %x\n", - gpio, edge); - return; - } - writel(val | (edge << (bit << 1)), reg); -} - -/* handle 32 interrupts in one status register */ -static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) -{ - u32 gpio_irq_no_base = port->virtual_irq_start; - - while (irq_stat != 0) { - int irqoffset = fls(irq_stat) - 1; - - if (port->both_edges & (1 << irqoffset)) - mxc_flip_edge(port, irqoffset); - - generic_handle_irq(gpio_irq_no_base + irqoffset); - - irq_stat &= ~(1 << irqoffset); - } -} - -/* MX1 and MX3 has one interrupt *per* gpio port */ -static void mx3_gpio_irq_handler(u32 irq, struct irq_desc *desc) -{ - u32 irq_stat; - struct mxc_gpio_port *port = irq_get_handler_data(irq); - - irq_stat = readl(port->base + GPIO_ISR) & readl(port->base + GPIO_IMR); - - mxc_gpio_irq_handler(port, irq_stat); -} - -/* MX2 has one interrupt *for all* gpio ports */ -static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc) -{ - u32 irq_msk, irq_stat; - struct mxc_gpio_port *port; - - /* walk through all interrupt status registers */ - list_for_each_entry(port, &mxc_gpio_ports, node) { - irq_msk = readl(port->base + GPIO_IMR); - if (!irq_msk) - continue; - - irq_stat = readl(port->base + GPIO_ISR) & irq_msk; - if (irq_stat) - mxc_gpio_irq_handler(port, irq_stat); - } -} - -/* - * Set interrupt number "irq" in the GPIO as a wake-up source. - * While system is running, all registered GPIO interrupts need to have - * wake-up enabled. When system is suspended, only selected GPIO interrupts - * need to have wake-up enabled. - * @param irq interrupt source number - * @param enable enable as wake-up if equal to non-zero - * @return This function returns 0 on success. - */ -static int gpio_set_wake_irq(struct irq_data *d, u32 enable) -{ - u32 gpio = irq_to_gpio(d->irq); - u32 gpio_idx = gpio & 0x1F; - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - struct mxc_gpio_port *port = gc->private; - - if (enable) { - if (port->irq_high && (gpio_idx >= 16)) - enable_irq_wake(port->irq_high); - else - enable_irq_wake(port->irq); - } else { - if (port->irq_high && (gpio_idx >= 16)) - disable_irq_wake(port->irq_high); - else - disable_irq_wake(port->irq); - } - - return 0; -} - -static void __init mxc_gpio_init_gc(struct mxc_gpio_port *port) -{ - struct irq_chip_generic *gc; - struct irq_chip_type *ct; - - gc = irq_alloc_generic_chip("gpio-mxc", 1, port->virtual_irq_start, - port->base, handle_level_irq); - gc->private = port; - - ct = gc->chip_types; - ct->chip.irq_ack = irq_gc_ack, - ct->chip.irq_mask = irq_gc_mask_clr_bit; - ct->chip.irq_unmask = irq_gc_mask_set_bit; - ct->chip.irq_set_type = gpio_set_irq_type; - ct->chip.irq_set_wake = gpio_set_wake_irq, - ct->regs.ack = GPIO_ISR; - ct->regs.mask = GPIO_IMR; - - irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK, - IRQ_NOREQUEST, 0); -} - -static void __devinit mxc_gpio_get_hw(struct platform_device *pdev) -{ - const struct of_device_id *of_id = - of_match_device(mxc_gpio_dt_ids, &pdev->dev); - enum mxc_gpio_hwtype hwtype; - - if (of_id) - pdev->id_entry = of_id->data; - hwtype = pdev->id_entry->driver_data; - - if (mxc_gpio_hwtype) { - /* - * The driver works with a reasonable presupposition, - * that is all gpio ports must be the same type when - * running on one soc. - */ - BUG_ON(mxc_gpio_hwtype != hwtype); - return; - } - - if (hwtype == IMX31_GPIO) - mxc_gpio_hwdata = &imx31_gpio_hwdata; - else - mxc_gpio_hwdata = &imx1_imx21_gpio_hwdata; - - mxc_gpio_hwtype = hwtype; -} - -static int __devinit mxc_gpio_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct mxc_gpio_port *port; - struct resource *iores; - int err; - - mxc_gpio_get_hw(pdev); - - port = kzalloc(sizeof(struct mxc_gpio_port), GFP_KERNEL); - if (!port) - return -ENOMEM; - - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iores) { - err = -ENODEV; - goto out_kfree; - } - - if (!request_mem_region(iores->start, resource_size(iores), - pdev->name)) { - err = -EBUSY; - goto out_kfree; - } - - port->base = ioremap(iores->start, resource_size(iores)); - if (!port->base) { - err = -ENOMEM; - goto out_release_mem; - } - - port->irq_high = platform_get_irq(pdev, 1); - port->irq = platform_get_irq(pdev, 0); - if (port->irq < 0) { - err = -EINVAL; - goto out_iounmap; - } - - /* disable the interrupt and clear the status */ - writel(0, port->base + GPIO_IMR); - writel(~0, port->base + GPIO_ISR); - - if (mxc_gpio_hwtype == IMX21_GPIO) { - /* setup one handler for all GPIO interrupts */ - if (pdev->id == 0) - irq_set_chained_handler(port->irq, - mx2_gpio_irq_handler); - } else { - /* setup one handler for each entry */ - irq_set_chained_handler(port->irq, mx3_gpio_irq_handler); - irq_set_handler_data(port->irq, port); - if (port->irq_high > 0) { - /* setup handler for GPIO 16 to 31 */ - irq_set_chained_handler(port->irq_high, - mx3_gpio_irq_handler); - irq_set_handler_data(port->irq_high, port); - } - } - - err = bgpio_init(&port->bgc, &pdev->dev, 4, - port->base + GPIO_PSR, - port->base + GPIO_DR, NULL, - port->base + GPIO_GDIR, NULL, false); - if (err) - goto out_iounmap; - - port->bgc.gc.base = pdev->id * 32; - port->bgc.dir = port->bgc.read_reg(port->bgc.reg_dir); - port->bgc.data = port->bgc.read_reg(port->bgc.reg_set); - - err = gpiochip_add(&port->bgc.gc); - if (err) - goto out_bgpio_remove; - - /* - * In dt case, we use gpio number range dynamically - * allocated by gpio core. - */ - port->virtual_irq_start = MXC_GPIO_IRQ_START + (np ? port->bgc.gc.base : - pdev->id * 32); - - /* gpio-mxc can be a generic irq chip */ - mxc_gpio_init_gc(port); - - list_add_tail(&port->node, &mxc_gpio_ports); - - return 0; - -out_bgpio_remove: - bgpio_remove(&port->bgc); -out_iounmap: - iounmap(port->base); -out_release_mem: - release_mem_region(iores->start, resource_size(iores)); -out_kfree: - kfree(port); - dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err); - return err; -} - -static struct platform_driver mxc_gpio_driver = { - .driver = { - .name = "gpio-mxc", - .owner = THIS_MODULE, - .of_match_table = mxc_gpio_dt_ids, - }, - .probe = mxc_gpio_probe, - .id_table = mxc_gpio_devtype, -}; - -static int __init gpio_mxc_init(void) -{ - return platform_driver_register(&mxc_gpio_driver); -} -postcore_initcall(gpio_mxc_init); - -MODULE_AUTHOR("Freescale Semiconductor, " - "Daniel Mack <danielncaiaq.de>, " - "Juergen Beisert <kernel@pengutronix.de>"); -MODULE_DESCRIPTION("Freescale MXC GPIO"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c deleted file mode 100644 index d8cafba8c82..00000000000 --- a/drivers/gpio/gpio-mxs.c +++ /dev/null @@ -1,289 +0,0 @@ -/* - * MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de> - * Copyright 2008 Juergen Beisert, kernel@pengutronix.de - * - * Based on code from Freescale, - * Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/gpio.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/basic_mmio_gpio.h> -#include <mach/mxs.h> - -#define MXS_SET 0x4 -#define MXS_CLR 0x8 - -#define PINCTRL_DOUT(n) ((cpu_is_mx23() ? 0x0500 : 0x0700) + (n) * 0x10) -#define PINCTRL_DIN(n) ((cpu_is_mx23() ? 0x0600 : 0x0900) + (n) * 0x10) -#define PINCTRL_DOE(n) ((cpu_is_mx23() ? 0x0700 : 0x0b00) + (n) * 0x10) -#define PINCTRL_PIN2IRQ(n) ((cpu_is_mx23() ? 0x0800 : 0x1000) + (n) * 0x10) -#define PINCTRL_IRQEN(n) ((cpu_is_mx23() ? 0x0900 : 0x1100) + (n) * 0x10) -#define PINCTRL_IRQLEV(n) ((cpu_is_mx23() ? 0x0a00 : 0x1200) + (n) * 0x10) -#define PINCTRL_IRQPOL(n) ((cpu_is_mx23() ? 0x0b00 : 0x1300) + (n) * 0x10) -#define PINCTRL_IRQSTAT(n) ((cpu_is_mx23() ? 0x0c00 : 0x1400) + (n) * 0x10) - -#define GPIO_INT_FALL_EDGE 0x0 -#define GPIO_INT_LOW_LEV 0x1 -#define GPIO_INT_RISE_EDGE 0x2 -#define GPIO_INT_HIGH_LEV 0x3 -#define GPIO_INT_LEV_MASK (1 << 0) -#define GPIO_INT_POL_MASK (1 << 1) - -struct mxs_gpio_port { - void __iomem *base; - int id; - int irq; - int virtual_irq_start; - struct bgpio_chip bgc; -}; - -/* Note: This driver assumes 32 GPIOs are handled in one register */ - -static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) -{ - u32 gpio = irq_to_gpio(d->irq); - u32 pin_mask = 1 << (gpio & 31); - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - struct mxs_gpio_port *port = gc->private; - void __iomem *pin_addr; - int edge; - - switch (type) { - case IRQ_TYPE_EDGE_RISING: - edge = GPIO_INT_RISE_EDGE; - break; - case IRQ_TYPE_EDGE_FALLING: - edge = GPIO_INT_FALL_EDGE; - break; - case IRQ_TYPE_LEVEL_LOW: - edge = GPIO_INT_LOW_LEV; - break; - case IRQ_TYPE_LEVEL_HIGH: - edge = GPIO_INT_HIGH_LEV; - break; - default: - return -EINVAL; - } - - /* set level or edge */ - pin_addr = port->base + PINCTRL_IRQLEV(port->id); - if (edge & GPIO_INT_LEV_MASK) - writel(pin_mask, pin_addr + MXS_SET); - else - writel(pin_mask, pin_addr + MXS_CLR); - - /* set polarity */ - pin_addr = port->base + PINCTRL_IRQPOL(port->id); - if (edge & GPIO_INT_POL_MASK) - writel(pin_mask, pin_addr + MXS_SET); - else - writel(pin_mask, pin_addr + MXS_CLR); - - writel(1 << (gpio & 0x1f), - port->base + PINCTRL_IRQSTAT(port->id) + MXS_CLR); - - return 0; -} - -/* MXS has one interrupt *per* gpio port */ -static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) -{ - u32 irq_stat; - struct mxs_gpio_port *port = irq_get_handler_data(irq); - u32 gpio_irq_no_base = port->virtual_irq_start; - - desc->irq_data.chip->irq_ack(&desc->irq_data); - - irq_stat = readl(port->base + PINCTRL_IRQSTAT(port->id)) & - readl(port->base + PINCTRL_IRQEN(port->id)); - - while (irq_stat != 0) { - int irqoffset = fls(irq_stat) - 1; - generic_handle_irq(gpio_irq_no_base + irqoffset); - irq_stat &= ~(1 << irqoffset); - } -} - -/* - * Set interrupt number "irq" in the GPIO as a wake-up source. - * While system is running, all registered GPIO interrupts need to have - * wake-up enabled. When system is suspended, only selected GPIO interrupts - * need to have wake-up enabled. - * @param irq interrupt source number - * @param enable enable as wake-up if equal to non-zero - * @return This function returns 0 on success. - */ -static int mxs_gpio_set_wake_irq(struct irq_data *d, unsigned int enable) -{ - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - struct mxs_gpio_port *port = gc->private; - - if (enable) - enable_irq_wake(port->irq); - else - disable_irq_wake(port->irq); - - return 0; -} - -static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port) -{ - struct irq_chip_generic *gc; - struct irq_chip_type *ct; - - gc = irq_alloc_generic_chip("gpio-mxs", 1, port->virtual_irq_start, - port->base, handle_level_irq); - gc->private = port; - - ct = gc->chip_types; - ct->chip.irq_ack = irq_gc_ack, - ct->chip.irq_mask = irq_gc_mask_clr_bit; - ct->chip.irq_unmask = irq_gc_mask_set_bit; - ct->chip.irq_set_type = mxs_gpio_set_irq_type; - ct->chip.irq_set_wake = mxs_gpio_set_wake_irq, - ct->regs.ack = PINCTRL_IRQSTAT(port->id) + MXS_CLR; - ct->regs.mask = PINCTRL_IRQEN(port->id); - - irq_setup_generic_chip(gc, IRQ_MSK(32), 0, IRQ_NOREQUEST, 0); -} - -static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset) -{ - struct bgpio_chip *bgc = to_bgpio_chip(gc); - struct mxs_gpio_port *port = - container_of(bgc, struct mxs_gpio_port, bgc); - - return port->virtual_irq_start + offset; -} - -static int __devinit mxs_gpio_probe(struct platform_device *pdev) -{ - static void __iomem *base; - struct mxs_gpio_port *port; - struct resource *iores = NULL; - int err; - - port = kzalloc(sizeof(struct mxs_gpio_port), GFP_KERNEL); - if (!port) - return -ENOMEM; - - port->id = pdev->id; - port->virtual_irq_start = MXS_GPIO_IRQ_START + port->id * 32; - - /* - * map memory region only once, as all the gpio ports - * share the same one - */ - if (!base) { - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iores) { - err = -ENODEV; - goto out_kfree; - } - - if (!request_mem_region(iores->start, resource_size(iores), - pdev->name)) { - err = -EBUSY; - goto out_kfree; - } - - base = ioremap(iores->start, resource_size(iores)); - if (!base) { - err = -ENOMEM; - goto out_release_mem; - } - } - port->base = base; - - port->irq = platform_get_irq(pdev, 0); - if (port->irq < 0) { - err = -EINVAL; - goto out_iounmap; - } - - /* - * select the pin interrupt functionality but initially - * disable the interrupts - */ - writel(~0U, port->base + PINCTRL_PIN2IRQ(port->id)); - writel(0, port->base + PINCTRL_IRQEN(port->id)); - - /* clear address has to be used to clear IRQSTAT bits */ - writel(~0U, port->base + PINCTRL_IRQSTAT(port->id) + MXS_CLR); - - /* gpio-mxs can be a generic irq chip */ - mxs_gpio_init_gc(port); - - /* setup one handler for each entry */ - irq_set_chained_handler(port->irq, mxs_gpio_irq_handler); - irq_set_handler_data(port->irq, port); - - err = bgpio_init(&port->bgc, &pdev->dev, 4, - port->base + PINCTRL_DIN(port->id), - port->base + PINCTRL_DOUT(port->id), NULL, - port->base + PINCTRL_DOE(port->id), NULL, false); - if (err) - goto out_iounmap; - - port->bgc.gc.to_irq = mxs_gpio_to_irq; - port->bgc.gc.base = port->id * 32; - - err = gpiochip_add(&port->bgc.gc); - if (err) - goto out_bgpio_remove; - - return 0; - -out_bgpio_remove: - bgpio_remove(&port->bgc); -out_iounmap: - if (iores) - iounmap(port->base); -out_release_mem: - if (iores) - release_mem_region(iores->start, resource_size(iores)); -out_kfree: - kfree(port); - dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err); - return err; -} - -static struct platform_driver mxs_gpio_driver = { - .driver = { - .name = "gpio-mxs", - .owner = THIS_MODULE, - }, - .probe = mxs_gpio_probe, -}; - -static int __init mxs_gpio_init(void) -{ - return platform_driver_register(&mxs_gpio_driver); -} -postcore_initcall(mxs_gpio_init); - -MODULE_AUTHOR("Freescale Semiconductor, " - "Daniel Mack <danielncaiaq.de>, " - "Juergen Beisert <kernel@pengutronix.de>"); -MODULE_DESCRIPTION("Freescale MXS GPIO"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 0599854e221..35bebde23e8 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -54,11 +54,6 @@ struct gpio_bank { struct device *dev; bool dbck_flag; int stride; - u32 width; - - void (*set_dataout)(struct gpio_bank *bank, int gpio, int enable); - - struct omap_gpio_reg_offs *regs; }; #ifdef CONFIG_ARCH_OMAP3 @@ -84,18 +79,121 @@ static struct omap3_gpio_regs gpio_context[OMAP34XX_NR_GPIOS]; */ static struct gpio_bank *gpio_bank; +static int bank_width; + /* TODO: Analyze removing gpio_bank_count usage from driver code */ int gpio_bank_count; -#define GPIO_INDEX(bank, gpio) (gpio % bank->width) -#define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio)) +static inline struct gpio_bank *get_gpio_bank(int gpio) +{ + if (cpu_is_omap15xx()) { + if (OMAP_GPIO_IS_MPUIO(gpio)) + return &gpio_bank[0]; + return &gpio_bank[1]; + } + if (cpu_is_omap16xx()) { + if (OMAP_GPIO_IS_MPUIO(gpio)) + return &gpio_bank[0]; + return &gpio_bank[1 + (gpio >> 4)]; + } + if (cpu_is_omap7xx()) { + if (OMAP_GPIO_IS_MPUIO(gpio)) + return &gpio_bank[0]; + return &gpio_bank[1 + (gpio >> 5)]; + } + if (cpu_is_omap24xx()) + return &gpio_bank[gpio >> 5]; + if (cpu_is_omap34xx() || cpu_is_omap44xx()) + return &gpio_bank[gpio >> 5]; + BUG(); + return NULL; +} + +static inline int get_gpio_index(int gpio) +{ + if (cpu_is_omap7xx()) + return gpio & 0x1f; + if (cpu_is_omap24xx()) + return gpio & 0x1f; + if (cpu_is_omap34xx() || cpu_is_omap44xx()) + return gpio & 0x1f; + return gpio & 0x0f; +} + +static inline int gpio_valid(int gpio) +{ + if (gpio < 0) + return -1; + if (cpu_class_is_omap1() && OMAP_GPIO_IS_MPUIO(gpio)) { + if (gpio >= OMAP_MAX_GPIO_LINES + 16) + return -1; + return 0; + } + if (cpu_is_omap15xx() && gpio < 16) + return 0; + if ((cpu_is_omap16xx()) && gpio < 64) + return 0; + if (cpu_is_omap7xx() && gpio < 192) + return 0; + if (cpu_is_omap2420() && gpio < 128) + return 0; + if (cpu_is_omap2430() && gpio < 160) + return 0; + if ((cpu_is_omap34xx() || cpu_is_omap44xx()) && gpio < 192) + return 0; + return -1; +} + +static int check_gpio(int gpio) +{ + if (unlikely(gpio_valid(gpio) < 0)) { + printk(KERN_ERR "omap-gpio: invalid GPIO %d\n", gpio); + dump_stack(); + return -1; + } + return 0; +} static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) { void __iomem *reg = bank->base; u32 l; - reg += bank->regs->direction; + switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP1 + case METHOD_MPUIO: + reg += OMAP_MPUIO_IO_CNTL / bank->stride; + break; +#endif +#ifdef CONFIG_ARCH_OMAP15XX + case METHOD_GPIO_1510: + reg += OMAP1510_GPIO_DIR_CONTROL; + break; +#endif +#ifdef CONFIG_ARCH_OMAP16XX + case METHOD_GPIO_1610: + reg += OMAP1610_GPIO_DIRECTION; + break; +#endif +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_DIR_CONTROL; + break; +#endif +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) + case METHOD_GPIO_24XX: + reg += OMAP24XX_GPIO_OE; + break; +#endif +#if defined(CONFIG_ARCH_OMAP4) + case METHOD_GPIO_44XX: + reg += OMAP4_GPIO_OE; + break; +#endif + default: + WARN_ON(1); + return; + } l = __raw_readl(reg); if (is_input) l |= 1 << gpio; @@ -104,48 +202,165 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) __raw_writel(l, reg); } - -/* set data out value using dedicate set/clear register */ -static void _set_gpio_dataout_reg(struct gpio_bank *bank, int gpio, int enable) +static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) { void __iomem *reg = bank->base; - u32 l = GPIO_BIT(bank, gpio); - - if (enable) - reg += bank->regs->set_dataout; - else - reg += bank->regs->clr_dataout; - - __raw_writel(l, reg); -} - -/* set data out value using mask register */ -static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable) -{ - void __iomem *reg = bank->base + bank->regs->dataout; - u32 gpio_bit = GPIO_BIT(bank, gpio); - u32 l; + u32 l = 0; - l = __raw_readl(reg); - if (enable) - l |= gpio_bit; - else - l &= ~gpio_bit; + switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP1 + case METHOD_MPUIO: + reg += OMAP_MPUIO_OUTPUT / bank->stride; + l = __raw_readl(reg); + if (enable) + l |= 1 << gpio; + else + l &= ~(1 << gpio); + break; +#endif +#ifdef CONFIG_ARCH_OMAP15XX + case METHOD_GPIO_1510: + reg += OMAP1510_GPIO_DATA_OUTPUT; + l = __raw_readl(reg); + if (enable) + l |= 1 << gpio; + else + l &= ~(1 << gpio); + break; +#endif +#ifdef CONFIG_ARCH_OMAP16XX + case METHOD_GPIO_1610: + if (enable) + reg += OMAP1610_GPIO_SET_DATAOUT; + else + reg += OMAP1610_GPIO_CLEAR_DATAOUT; + l = 1 << gpio; + break; +#endif +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_DATA_OUTPUT; + l = __raw_readl(reg); + if (enable) + l |= 1 << gpio; + else + l &= ~(1 << gpio); + break; +#endif +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) + case METHOD_GPIO_24XX: + if (enable) + reg += OMAP24XX_GPIO_SETDATAOUT; + else + reg += OMAP24XX_GPIO_CLEARDATAOUT; + l = 1 << gpio; + break; +#endif +#ifdef CONFIG_ARCH_OMAP4 + case METHOD_GPIO_44XX: + if (enable) + reg += OMAP4_GPIO_SETDATAOUT; + else + reg += OMAP4_GPIO_CLEARDATAOUT; + l = 1 << gpio; + break; +#endif + default: + WARN_ON(1); + return; + } __raw_writel(l, reg); } static int _get_gpio_datain(struct gpio_bank *bank, int gpio) { - void __iomem *reg = bank->base + bank->regs->datain; + void __iomem *reg; - return (__raw_readl(reg) & GPIO_BIT(bank, gpio)) != 0; + if (check_gpio(gpio) < 0) + return -EINVAL; + reg = bank->base; + switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP1 + case METHOD_MPUIO: + reg += OMAP_MPUIO_INPUT_LATCH / bank->stride; + break; +#endif +#ifdef CONFIG_ARCH_OMAP15XX + case METHOD_GPIO_1510: + reg += OMAP1510_GPIO_DATA_INPUT; + break; +#endif +#ifdef CONFIG_ARCH_OMAP16XX + case METHOD_GPIO_1610: + reg += OMAP1610_GPIO_DATAIN; + break; +#endif +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_DATA_INPUT; + break; +#endif +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) + case METHOD_GPIO_24XX: + reg += OMAP24XX_GPIO_DATAIN; + break; +#endif +#ifdef CONFIG_ARCH_OMAP4 + case METHOD_GPIO_44XX: + reg += OMAP4_GPIO_DATAIN; + break; +#endif + default: + return -EINVAL; + } + return (__raw_readl(reg) + & (1 << get_gpio_index(gpio))) != 0; } static int _get_gpio_dataout(struct gpio_bank *bank, int gpio) { - void __iomem *reg = bank->base + bank->regs->dataout; + void __iomem *reg; + + if (check_gpio(gpio) < 0) + return -EINVAL; + reg = bank->base; + + switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP1 + case METHOD_MPUIO: + reg += OMAP_MPUIO_OUTPUT / bank->stride; + break; +#endif +#ifdef CONFIG_ARCH_OMAP15XX + case METHOD_GPIO_1510: + reg += OMAP1510_GPIO_DATA_OUTPUT; + break; +#endif +#ifdef CONFIG_ARCH_OMAP16XX + case METHOD_GPIO_1610: + reg += OMAP1610_GPIO_DATAOUT; + break; +#endif +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_DATA_OUTPUT; + break; +#endif +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) + case METHOD_GPIO_24XX: + reg += OMAP24XX_GPIO_DATAOUT; + break; +#endif +#ifdef CONFIG_ARCH_OMAP4 + case METHOD_GPIO_44XX: + reg += OMAP4_GPIO_DATAOUT; + break; +#endif + default: + return -EINVAL; + } - return (__raw_readl(reg) & GPIO_BIT(bank, gpio)) != 0; + return (__raw_readl(reg) & (1 << get_gpio_index(gpio))) != 0; } #define MOD_REG_BIT(reg, bit_mask, set) \ @@ -168,7 +383,7 @@ do { \ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, unsigned debounce) { - void __iomem *reg; + void __iomem *reg = bank->base; u32 val; u32 l; @@ -182,12 +397,21 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, else debounce = (debounce / 0x1f) - 1; - l = GPIO_BIT(bank, gpio); + l = 1 << get_gpio_index(gpio); + + if (bank->method == METHOD_GPIO_44XX) + reg += OMAP4_GPIO_DEBOUNCINGTIME; + else + reg += OMAP24XX_GPIO_DEBOUNCE_VAL; - reg = bank->base + bank->regs->debounce; __raw_writel(debounce, reg); - reg = bank->base + bank->regs->debounce_en; + reg = bank->base; + if (bank->method == METHOD_GPIO_44XX) + reg += OMAP4_GPIO_DEBOUNCENABLE; + else + reg += OMAP24XX_GPIO_DEBOUNCE_EN; + val = __raw_readl(reg); if (debounce) { @@ -405,6 +629,9 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) else gpio = d->irq - IH_GPIO_BASE; + if (check_gpio(gpio) < 0) + return -EINVAL; + if (type & ~IRQ_TYPE_SENSE_MASK) return -EINVAL; @@ -415,7 +642,7 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) bank = irq_data_get_irq_chip_data(d); spin_lock_irqsave(&bank->lock, flags); - retval = _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), type); + retval = _set_gpio_triggering(bank, get_gpio_index(gpio), type); spin_unlock_irqrestore(&bank->lock, flags); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) @@ -430,81 +657,195 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) { void __iomem *reg = bank->base; - reg += bank->regs->irqstatus; + switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP1 + case METHOD_MPUIO: + /* MPUIO irqstatus is reset by reading the status register, + * so do nothing here */ + return; +#endif +#ifdef CONFIG_ARCH_OMAP15XX + case METHOD_GPIO_1510: + reg += OMAP1510_GPIO_INT_STATUS; + break; +#endif +#ifdef CONFIG_ARCH_OMAP16XX + case METHOD_GPIO_1610: + reg += OMAP1610_GPIO_IRQSTATUS1; + break; +#endif +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_INT_STATUS; + break; +#endif +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) + case METHOD_GPIO_24XX: + reg += OMAP24XX_GPIO_IRQSTATUS1; + break; +#endif +#if defined(CONFIG_ARCH_OMAP4) + case METHOD_GPIO_44XX: + reg += OMAP4_GPIO_IRQSTATUS0; + break; +#endif + default: + WARN_ON(1); + return; + } __raw_writel(gpio_mask, reg); /* Workaround for clearing DSP GPIO interrupts to allow retention */ - if (bank->regs->irqstatus2) { - reg = bank->base + bank->regs->irqstatus2; + if (cpu_is_omap24xx() || cpu_is_omap34xx()) + reg = bank->base + OMAP24XX_GPIO_IRQSTATUS2; + else if (cpu_is_omap44xx()) + reg = bank->base + OMAP4_GPIO_IRQSTATUS1; + + if (cpu_is_omap24xx() || cpu_is_omap34xx() || cpu_is_omap44xx()) { __raw_writel(gpio_mask, reg); - } /* Flush posted write for the irq status to avoid spurious interrupts */ __raw_readl(reg); + } } static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio) { - _clear_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); + _clear_gpio_irqbank(bank, 1 << get_gpio_index(gpio)); } static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank) { void __iomem *reg = bank->base; + int inv = 0; u32 l; - u32 mask = (1 << bank->width) - 1; + u32 mask; + + switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP1 + case METHOD_MPUIO: + reg += OMAP_MPUIO_GPIO_MASKIT / bank->stride; + mask = 0xffff; + inv = 1; + break; +#endif +#ifdef CONFIG_ARCH_OMAP15XX + case METHOD_GPIO_1510: + reg += OMAP1510_GPIO_INT_MASK; + mask = 0xffff; + inv = 1; + break; +#endif +#ifdef CONFIG_ARCH_OMAP16XX + case METHOD_GPIO_1610: + reg += OMAP1610_GPIO_IRQENABLE1; + mask = 0xffff; + break; +#endif +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_INT_MASK; + mask = 0xffffffff; + inv = 1; + break; +#endif +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) + case METHOD_GPIO_24XX: + reg += OMAP24XX_GPIO_IRQENABLE1; + mask = 0xffffffff; + break; +#endif +#if defined(CONFIG_ARCH_OMAP4) + case METHOD_GPIO_44XX: + reg += OMAP4_GPIO_IRQSTATUSSET0; + mask = 0xffffffff; + break; +#endif + default: + WARN_ON(1); + return 0; + } - reg += bank->regs->irqenable; l = __raw_readl(reg); - if (bank->regs->irqenable_inv) + if (inv) l = ~l; l &= mask; return l; } -static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) +static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable) { void __iomem *reg = bank->base; u32 l; - if (bank->regs->set_irqenable) { - reg += bank->regs->set_irqenable; - l = gpio_mask; - } else { - reg += bank->regs->irqenable; + switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP1 + case METHOD_MPUIO: + reg += OMAP_MPUIO_GPIO_MASKIT / bank->stride; l = __raw_readl(reg); - if (bank->regs->irqenable_inv) - l &= ~gpio_mask; + if (enable) + l &= ~(gpio_mask); else l |= gpio_mask; - } - - __raw_writel(l, reg); -} - -static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) -{ - void __iomem *reg = bank->base; - u32 l; - - if (bank->regs->clr_irqenable) { - reg += bank->regs->clr_irqenable; + break; +#endif +#ifdef CONFIG_ARCH_OMAP15XX + case METHOD_GPIO_1510: + reg += OMAP1510_GPIO_INT_MASK; + l = __raw_readl(reg); + if (enable) + l &= ~(gpio_mask); + else + l |= gpio_mask; + break; +#endif +#ifdef CONFIG_ARCH_OMAP16XX + case METHOD_GPIO_1610: + if (enable) + reg += OMAP1610_GPIO_SET_IRQENABLE1; + else + reg += OMAP1610_GPIO_CLEAR_IRQENABLE1; l = gpio_mask; - } else { - reg += bank->regs->irqenable; + break; +#endif +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_INT_MASK; l = __raw_readl(reg); - if (bank->regs->irqenable_inv) + if (enable) + l &= ~(gpio_mask); + else l |= gpio_mask; + break; +#endif +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) + case METHOD_GPIO_24XX: + if (enable) + reg += OMAP24XX_GPIO_SETIRQENABLE1; + else + reg += OMAP24XX_GPIO_CLEARIRQENABLE1; + l = gpio_mask; + break; +#endif +#ifdef CONFIG_ARCH_OMAP4 + case METHOD_GPIO_44XX: + if (enable) + reg += OMAP4_GPIO_IRQSTATUSSET0; else - l &= ~gpio_mask; + reg += OMAP4_GPIO_IRQSTATUSCLR0; + l = gpio_mask; + break; +#endif + default: + WARN_ON(1); + return; } - __raw_writel(l, reg); } static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) { - _enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); + _enable_gpio_irqbank(bank, 1 << get_gpio_index(gpio), enable); } /* @@ -517,32 +858,50 @@ static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int ena */ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) { - u32 gpio_bit = GPIO_BIT(bank, gpio); - unsigned long flags; + unsigned long uninitialized_var(flags); - if (bank->non_wakeup_gpios & gpio_bit) { - dev_err(bank->dev, - "Unable to modify wakeup on non-wakeup GPIO%d\n", gpio); + switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP16XX + case METHOD_MPUIO: + case METHOD_GPIO_1610: + spin_lock_irqsave(&bank->lock, flags); + if (enable) + bank->suspend_wakeup |= (1 << gpio); + else + bank->suspend_wakeup &= ~(1 << gpio); + spin_unlock_irqrestore(&bank->lock, flags); + return 0; +#endif +#ifdef CONFIG_ARCH_OMAP2PLUS + case METHOD_GPIO_24XX: + case METHOD_GPIO_44XX: + if (bank->non_wakeup_gpios & (1 << gpio)) { + printk(KERN_ERR "Unable to modify wakeup on " + "non-wakeup GPIO%d\n", + (bank - gpio_bank) * 32 + gpio); + return -EINVAL; + } + spin_lock_irqsave(&bank->lock, flags); + if (enable) + bank->suspend_wakeup |= (1 << gpio); + else + bank->suspend_wakeup &= ~(1 << gpio); + spin_unlock_irqrestore(&bank->lock, flags); + return 0; +#endif + default: + printk(KERN_ERR "Can't enable GPIO wakeup for method %i\n", + bank->method); return -EINVAL; } - - spin_lock_irqsave(&bank->lock, flags); - if (enable) - bank->suspend_wakeup |= gpio_bit; - else - bank->suspend_wakeup &= ~gpio_bit; - - spin_unlock_irqrestore(&bank->lock, flags); - - return 0; } static void _reset_gpio(struct gpio_bank *bank, int gpio) { - _set_gpio_direction(bank, GPIO_INDEX(bank, gpio), 1); + _set_gpio_direction(bank, get_gpio_index(gpio), 1); _set_gpio_irqenable(bank, gpio, 0); _clear_gpio_irqstatus(bank, gpio); - _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE); + _set_gpio_triggering(bank, get_gpio_index(gpio), IRQ_TYPE_NONE); } /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ @@ -552,8 +911,10 @@ static int gpio_wake_enable(struct irq_data *d, unsigned int enable) struct gpio_bank *bank; int retval; + if (check_gpio(gpio) < 0) + return -ENODEV; bank = irq_data_get_irq_chip_data(d); - retval = _set_gpio_wakeup(bank, gpio, enable); + retval = _set_gpio_wakeup(bank, get_gpio_index(gpio), enable); return retval; } @@ -669,7 +1030,31 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) chained_irq_enter(chip, desc); bank = irq_get_handler_data(irq); - isr_reg = bank->base + bank->regs->irqstatus; +#ifdef CONFIG_ARCH_OMAP1 + if (bank->method == METHOD_MPUIO) + isr_reg = bank->base + + OMAP_MPUIO_GPIO_INT / bank->stride; +#endif +#ifdef CONFIG_ARCH_OMAP15XX + if (bank->method == METHOD_GPIO_1510) + isr_reg = bank->base + OMAP1510_GPIO_INT_STATUS; +#endif +#if defined(CONFIG_ARCH_OMAP16XX) + if (bank->method == METHOD_GPIO_1610) + isr_reg = bank->base + OMAP1610_GPIO_IRQSTATUS1; +#endif +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + if (bank->method == METHOD_GPIO_7XX) + isr_reg = bank->base + OMAP7XX_GPIO_INT_STATUS; +#endif +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) + if (bank->method == METHOD_GPIO_24XX) + isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1; +#endif +#if defined(CONFIG_ARCH_OMAP4) + if (bank->method == METHOD_GPIO_44XX) + isr_reg = bank->base + OMAP4_GPIO_IRQSTATUS0; +#endif if (WARN_ON(!isr_reg)) goto exit; @@ -691,9 +1076,9 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) /* clear edge sensitive interrupts before handler(s) are called so that we don't miss any interrupt occurred while executing them */ - _disable_gpio_irqbank(bank, isr_saved & ~level_mask); + _enable_gpio_irqbank(bank, isr_saved & ~level_mask, 0); _clear_gpio_irqbank(bank, isr_saved & ~level_mask); - _enable_gpio_irqbank(bank, isr_saved & ~level_mask); + _enable_gpio_irqbank(bank, isr_saved & ~level_mask, 1); /* if there is only edge sensitive GPIO pin interrupts configured, we could unmask GPIO bank interrupt immediately */ @@ -709,7 +1094,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) gpio_irq = bank->virtual_irq_start; for (; isr != 0; isr >>= 1, gpio_irq++) { - gpio_index = GPIO_INDEX(bank, irq_to_gpio(gpio_irq)); + gpio_index = get_gpio_index(irq_to_gpio(gpio_irq)); if (!(isr & 1)) continue; @@ -765,7 +1150,7 @@ static void gpio_mask_irq(struct irq_data *d) spin_lock_irqsave(&bank->lock, flags); _set_gpio_irqenable(bank, gpio, 0); - _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE); + _set_gpio_triggering(bank, get_gpio_index(gpio), IRQ_TYPE_NONE); spin_unlock_irqrestore(&bank->lock, flags); } @@ -773,13 +1158,13 @@ static void gpio_unmask_irq(struct irq_data *d) { unsigned int gpio = d->irq - IH_GPIO_BASE; struct gpio_bank *bank = irq_data_get_irq_chip_data(d); - unsigned int irq_mask = GPIO_BIT(bank, gpio); + unsigned int irq_mask = 1 << get_gpio_index(gpio); u32 trigger = irqd_get_trigger_type(d); unsigned long flags; spin_lock_irqsave(&bank->lock, flags); if (trigger) - _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), trigger); + _set_gpio_triggering(bank, get_gpio_index(gpio), trigger); /* For level-triggered GPIOs, the clearing must be done after * the HW source is cleared, thus after the handler has run */ @@ -806,8 +1191,45 @@ static struct irq_chip gpio_irq_chip = { #ifdef CONFIG_ARCH_OMAP1 +/* MPUIO uses the always-on 32k clock */ + +static void mpuio_ack_irq(struct irq_data *d) +{ + /* The ISR is reset automatically, so do nothing here. */ +} + +static void mpuio_mask_irq(struct irq_data *d) +{ + unsigned int gpio = OMAP_MPUIO(d->irq - IH_MPUIO_BASE); + struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + + _set_gpio_irqenable(bank, gpio, 0); +} + +static void mpuio_unmask_irq(struct irq_data *d) +{ + unsigned int gpio = OMAP_MPUIO(d->irq - IH_MPUIO_BASE); + struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + + _set_gpio_irqenable(bank, gpio, 1); +} + +static struct irq_chip mpuio_irq_chip = { + .name = "MPUIO", + .irq_ack = mpuio_ack_irq, + .irq_mask = mpuio_mask_irq, + .irq_unmask = mpuio_unmask_irq, + .irq_set_type = gpio_irq_type, +#ifdef CONFIG_ARCH_OMAP16XX + /* REVISIT: assuming only 16xx supports MPUIO wake events */ + .irq_set_wake = gpio_wake_enable, +#endif +}; + + #define bank_is_mpuio(bank) ((bank)->method == METHOD_MPUIO) + #ifdef CONFIG_ARCH_OMAP16XX #include <linux/platform_device.h> @@ -867,7 +1289,7 @@ static struct platform_device omap_mpuio_device = { static inline void mpuio_init(void) { - struct gpio_bank *bank = &gpio_bank[0]; + struct gpio_bank *bank = get_gpio_bank(OMAP_MPUIO(0)); platform_set_drvdata(&omap_mpuio_device, bank); if (platform_driver_register(&omap_mpuio_driver) == 0) @@ -880,6 +1302,8 @@ static inline void mpuio_init(void) {} #else +extern struct irq_chip mpuio_irq_chip; + #define bank_is_mpuio(bank) 0 static inline void mpuio_init(void) {} @@ -905,8 +1329,31 @@ static int gpio_input(struct gpio_chip *chip, unsigned offset) static int gpio_is_input(struct gpio_bank *bank, int mask) { - void __iomem *reg = bank->base + bank->regs->direction; + void __iomem *reg = bank->base; + switch (bank->method) { + case METHOD_MPUIO: + reg += OMAP_MPUIO_IO_CNTL / bank->stride; + break; + case METHOD_GPIO_1510: + reg += OMAP1510_GPIO_DIR_CONTROL; + break; + case METHOD_GPIO_1610: + reg += OMAP1610_GPIO_DIRECTION; + break; + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_DIR_CONTROL; + break; + case METHOD_GPIO_24XX: + reg += OMAP24XX_GPIO_OE; + break; + case METHOD_GPIO_44XX: + reg += OMAP4_GPIO_OE; + break; + default: + WARN_ONCE(1, "gpio_is_input: incorrect OMAP GPIO method"); + return -EINVAL; + } return __raw_readl(reg) & mask; } @@ -918,9 +1365,9 @@ static int gpio_get(struct gpio_chip *chip, unsigned offset) u32 mask; gpio = chip->base + offset; - bank = container_of(chip, struct gpio_bank, chip); + bank = get_gpio_bank(gpio); reg = bank->base; - mask = GPIO_BIT(bank, gpio); + mask = 1 << get_gpio_index(gpio); if (gpio_is_input(bank, mask)) return _get_gpio_datain(bank, gpio); @@ -935,7 +1382,7 @@ static int gpio_output(struct gpio_chip *chip, unsigned offset, int value) bank = container_of(chip, struct gpio_bank, chip); spin_lock_irqsave(&bank->lock, flags); - bank->set_dataout(bank, offset, value); + _set_gpio_dataout(bank, offset, value); _set_gpio_direction(bank, offset, 0); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -969,7 +1416,7 @@ static void gpio_set(struct gpio_chip *chip, unsigned offset, int value) bank = container_of(chip, struct gpio_bank, chip); spin_lock_irqsave(&bank->lock, flags); - bank->set_dataout(bank, offset, value); + _set_gpio_dataout(bank, offset, value); spin_unlock_irqrestore(&bank->lock, flags); } @@ -985,17 +1432,19 @@ static int gpio_2irq(struct gpio_chip *chip, unsigned offset) static void __init omap_gpio_show_rev(struct gpio_bank *bank) { - static bool called; u32 rev; - if (called || bank->regs->revision == USHRT_MAX) + if (cpu_is_omap16xx() && !(bank->method != METHOD_MPUIO)) + rev = __raw_readw(bank->base + OMAP1610_GPIO_REVISION); + else if (cpu_is_omap24xx() || cpu_is_omap34xx()) + rev = __raw_readl(bank->base + OMAP24XX_GPIO_REVISION); + else if (cpu_is_omap44xx()) + rev = __raw_readl(bank->base + OMAP4_GPIO_REVISION); + else return; - rev = __raw_readw(bank->base + bank->regs->revision); - pr_info("OMAP GPIO hardware version %d.%d\n", + printk(KERN_INFO "OMAP GPIO hardware version %d.%d\n", (rev >> 4) & 0x0f, rev & 0x0f); - - called = true; } /* This lock class tells lockdep that GPIO irqs are in a different @@ -1077,30 +1526,6 @@ static void omap_gpio_mod_init(struct gpio_bank *bank, int id) } } -static __init void -omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start, - unsigned int num) -{ - struct irq_chip_generic *gc; - struct irq_chip_type *ct; - - gc = irq_alloc_generic_chip("MPUIO", 1, irq_start, bank->base, - handle_simple_irq); - ct = gc->chip_types; - - /* NOTE: No ack required, reading IRQ status clears it. */ - ct->chip.irq_mask = irq_gc_mask_set_bit; - ct->chip.irq_unmask = irq_gc_mask_clr_bit; - ct->chip.irq_set_type = gpio_irq_type; - /* REVISIT: assuming only 16xx supports MPUIO wake events */ - if (cpu_is_omap16xx()) - ct->chip.irq_set_wake = gpio_wake_enable, - - ct->regs.mask = OMAP_MPUIO_GPIO_INT / bank->stride; - irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, - IRQ_NOREQUEST | IRQ_NOPROBE, 0); -} - static void __devinit omap_gpio_chip_init(struct gpio_bank *bank) { int j; @@ -1128,23 +1553,22 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank) } else { bank->chip.label = "gpio"; bank->chip.base = gpio; - gpio += bank->width; + gpio += bank_width; } - bank->chip.ngpio = bank->width; + bank->chip.ngpio = bank_width; gpiochip_add(&bank->chip); for (j = bank->virtual_irq_start; - j < bank->virtual_irq_start + bank->width; j++) { + j < bank->virtual_irq_start + bank_width; j++) { irq_set_lockdep_class(j, &gpio_lock_class); irq_set_chip_data(j, bank); - if (bank_is_mpuio(bank)) { - omap_mpuio_alloc_gc(bank, j, bank->width); - } else { + if (bank_is_mpuio(bank)) + irq_set_chip(j, &mpuio_irq_chip); + else irq_set_chip(j, &gpio_irq_chip); - irq_set_handler(j, handle_simple_irq); - set_irq_flags(j, IRQF_VALID); - } + irq_set_handler(j, handle_simple_irq); + set_irq_flags(j, IRQF_VALID); } irq_set_chained_handler(bank->irq, gpio_irq_handler); irq_set_handler_data(bank->irq, bank); @@ -1186,14 +1610,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) bank->dev = &pdev->dev; bank->dbck_flag = pdata->dbck_flag; bank->stride = pdata->bank_stride; - bank->width = pdata->bank_width; - - bank->regs = pdata->regs; - - if (bank->regs->set_dataout && bank->regs->clr_dataout) - bank->set_dataout = _set_gpio_dataout_reg; - else - bank->set_dataout = _set_gpio_dataout_mask; + bank_width = pdata->bank_width; spin_lock_init(&bank->lock); diff --git a/drivers/gpio/gpio-plat-samsung.c b/drivers/gpio/gpio-plat-samsung.c index ef67f1952a7..ea37c046178 100644 --- a/drivers/gpio/gpio-plat-samsung.c +++ b/drivers/gpio/gpio-plat-samsung.c @@ -1,4 +1,5 @@ -/* +/* arch/arm/plat-samsung/gpiolib.c + * * Copyright 2008 Openmoko, Inc. * Copyright 2008 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> diff --git a/drivers/gpio/gpio-s5pc100.c b/drivers/gpio/gpio-s5pc100.c index 7f87b0c76e0..2842394b28b 100644 --- a/drivers/gpio/gpio-s5pc100.c +++ b/drivers/gpio/gpio-s5pc100.c @@ -1,5 +1,4 @@ -/* - * S5PC100 - GPIOlib support +/* linux/arch/arm/mach-s5pc100/gpiolib.c * * Copyright (c) 2010 Samsung Electronics Co., Ltd. * http://www.samsung.com @@ -7,6 +6,8 @@ * Copyright 2009 Samsung Electronics Co * Kyungmin Park <kyungmin.park@samsung.com> * + * S5PC100 - GPIOlib support + * * 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. diff --git a/drivers/gpio/gpio-s5pv210.c b/drivers/gpio/gpio-s5pv210.c index eb12f1602de..1ba20a703e0 100644 --- a/drivers/gpio/gpio-s5pv210.c +++ b/drivers/gpio/gpio-s5pv210.c @@ -1,9 +1,10 @@ -/* - * S5PV210 - GPIOlib support +/* linux/arch/arm/mach-s5pv210/gpiolib.c * * Copyright (c) 2010 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * + * S5PV210 - GPIOlib support + * * 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. diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c deleted file mode 100644 index 747eb40e8af..00000000000 --- a/drivers/gpio/gpio-tegra.c +++ /dev/null @@ -1,441 +0,0 @@ -/* - * arch/arm/mach-tegra/gpio.c - * - * Copyright (c) 2010 Google, Inc - * - * Author: - * Erik Gilling <konkers@google.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/init.h> -#include <linux/irq.h> -#include <linux/interrupt.h> - -#include <linux/io.h> -#include <linux/gpio.h> -#include <linux/of.h> - -#include <asm/mach/irq.h> - -#include <mach/iomap.h> -#include <mach/suspend.h> - -#define GPIO_BANK(x) ((x) >> 5) -#define GPIO_PORT(x) (((x) >> 3) & 0x3) -#define GPIO_BIT(x) ((x) & 0x7) - -#define GPIO_REG(x) (IO_TO_VIRT(TEGRA_GPIO_BASE) + \ - GPIO_BANK(x) * 0x80 + \ - GPIO_PORT(x) * 4) - -#define GPIO_CNF(x) (GPIO_REG(x) + 0x00) -#define GPIO_OE(x) (GPIO_REG(x) + 0x10) -#define GPIO_OUT(x) (GPIO_REG(x) + 0X20) -#define GPIO_IN(x) (GPIO_REG(x) + 0x30) -#define GPIO_INT_STA(x) (GPIO_REG(x) + 0x40) -#define GPIO_INT_ENB(x) (GPIO_REG(x) + 0x50) -#define GPIO_INT_LVL(x) (GPIO_REG(x) + 0x60) -#define GPIO_INT_CLR(x) (GPIO_REG(x) + 0x70) - -#define GPIO_MSK_CNF(x) (GPIO_REG(x) + 0x800) -#define GPIO_MSK_OE(x) (GPIO_REG(x) + 0x810) -#define GPIO_MSK_OUT(x) (GPIO_REG(x) + 0X820) -#define GPIO_MSK_INT_STA(x) (GPIO_REG(x) + 0x840) -#define GPIO_MSK_INT_ENB(x) (GPIO_REG(x) + 0x850) -#define GPIO_MSK_INT_LVL(x) (GPIO_REG(x) + 0x860) - -#define GPIO_INT_LVL_MASK 0x010101 -#define GPIO_INT_LVL_EDGE_RISING 0x000101 -#define GPIO_INT_LVL_EDGE_FALLING 0x000100 -#define GPIO_INT_LVL_EDGE_BOTH 0x010100 -#define GPIO_INT_LVL_LEVEL_HIGH 0x000001 -#define GPIO_INT_LVL_LEVEL_LOW 0x000000 - -struct tegra_gpio_bank { - int bank; - int irq; - spinlock_t lvl_lock[4]; -#ifdef CONFIG_PM - u32 cnf[4]; - u32 out[4]; - u32 oe[4]; - u32 int_enb[4]; - u32 int_lvl[4]; -#endif -}; - - -static struct tegra_gpio_bank tegra_gpio_banks[] = { - {.bank = 0, .irq = INT_GPIO1}, - {.bank = 1, .irq = INT_GPIO2}, - {.bank = 2, .irq = INT_GPIO3}, - {.bank = 3, .irq = INT_GPIO4}, - {.bank = 4, .irq = INT_GPIO5}, - {.bank = 5, .irq = INT_GPIO6}, - {.bank = 6, .irq = INT_GPIO7}, -}; - -static int tegra_gpio_compose(int bank, int port, int bit) -{ - return (bank << 5) | ((port & 0x3) << 3) | (bit & 0x7); -} - -static void tegra_gpio_mask_write(u32 reg, int gpio, int value) -{ - u32 val; - - val = 0x100 << GPIO_BIT(gpio); - if (value) - val |= 1 << GPIO_BIT(gpio); - __raw_writel(val, reg); -} - -void tegra_gpio_enable(int gpio) -{ - tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1); -} - -void tegra_gpio_disable(int gpio) -{ - tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0); -} - -static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - tegra_gpio_mask_write(GPIO_MSK_OUT(offset), offset, value); -} - -static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - return (__raw_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1; -} - -static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 0); - return 0; -} - -static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset, - int value) -{ - tegra_gpio_set(chip, offset, value); - tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 1); - return 0; -} - - - -static struct gpio_chip tegra_gpio_chip = { - .label = "tegra-gpio", - .direction_input = tegra_gpio_direction_input, - .get = tegra_gpio_get, - .direction_output = tegra_gpio_direction_output, - .set = tegra_gpio_set, - .base = 0, - .ngpio = TEGRA_NR_GPIOS, -}; - -static void tegra_gpio_irq_ack(struct irq_data *d) -{ - int gpio = d->irq - INT_GPIO_BASE; - - __raw_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio)); -} - -static void tegra_gpio_irq_mask(struct irq_data *d) -{ - int gpio = d->irq - INT_GPIO_BASE; - - tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0); -} - -static void tegra_gpio_irq_unmask(struct irq_data *d) -{ - int gpio = d->irq - INT_GPIO_BASE; - - tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1); -} - -static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) -{ - int gpio = d->irq - INT_GPIO_BASE; - struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); - int port = GPIO_PORT(gpio); - int lvl_type; - int val; - unsigned long flags; - - switch (type & IRQ_TYPE_SENSE_MASK) { - case IRQ_TYPE_EDGE_RISING: - lvl_type = GPIO_INT_LVL_EDGE_RISING; - break; - - case IRQ_TYPE_EDGE_FALLING: - lvl_type = GPIO_INT_LVL_EDGE_FALLING; - break; - - case IRQ_TYPE_EDGE_BOTH: - lvl_type = GPIO_INT_LVL_EDGE_BOTH; - break; - - case IRQ_TYPE_LEVEL_HIGH: - lvl_type = GPIO_INT_LVL_LEVEL_HIGH; - break; - - case IRQ_TYPE_LEVEL_LOW: - lvl_type = GPIO_INT_LVL_LEVEL_LOW; - break; - - default: - return -EINVAL; - } - - spin_lock_irqsave(&bank->lvl_lock[port], flags); - - val = __raw_readl(GPIO_INT_LVL(gpio)); - val &= ~(GPIO_INT_LVL_MASK << GPIO_BIT(gpio)); - val |= lvl_type << GPIO_BIT(gpio); - __raw_writel(val, GPIO_INT_LVL(gpio)); - - spin_unlock_irqrestore(&bank->lvl_lock[port], flags); - - if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __irq_set_handler_locked(d->irq, handle_level_irq); - else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) - __irq_set_handler_locked(d->irq, handle_edge_irq); - - return 0; -} - -static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - struct tegra_gpio_bank *bank; - int port; - int pin; - int unmasked = 0; - struct irq_chip *chip = irq_desc_get_chip(desc); - - chained_irq_enter(chip, desc); - - bank = irq_get_handler_data(irq); - - for (port = 0; port < 4; port++) { - int gpio = tegra_gpio_compose(bank->bank, port, 0); - unsigned long sta = __raw_readl(GPIO_INT_STA(gpio)) & - __raw_readl(GPIO_INT_ENB(gpio)); - u32 lvl = __raw_readl(GPIO_INT_LVL(gpio)); - - for_each_set_bit(pin, &sta, 8) { - __raw_writel(1 << pin, GPIO_INT_CLR(gpio)); - - /* if gpio is edge triggered, clear condition - * before executing the hander so that we don't - * miss edges - */ - if (lvl & (0x100 << pin)) { - unmasked = 1; - chained_irq_exit(chip, desc); - } - - generic_handle_irq(gpio_to_irq(gpio + pin)); - } - } - - if (!unmasked) - chained_irq_exit(chip, desc); - -} - -#ifdef CONFIG_PM -void tegra_gpio_resume(void) -{ - unsigned long flags; - int b; - int p; - - local_irq_save(flags); - - for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { - struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; - - for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { - unsigned int gpio = (b<<5) | (p<<3); - __raw_writel(bank->cnf[p], GPIO_CNF(gpio)); - __raw_writel(bank->out[p], GPIO_OUT(gpio)); - __raw_writel(bank->oe[p], GPIO_OE(gpio)); - __raw_writel(bank->int_lvl[p], GPIO_INT_LVL(gpio)); - __raw_writel(bank->int_enb[p], GPIO_INT_ENB(gpio)); - } - } - - local_irq_restore(flags); -} - -void tegra_gpio_suspend(void) -{ - unsigned long flags; - int b; - int p; - - local_irq_save(flags); - for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { - struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; - - for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { - unsigned int gpio = (b<<5) | (p<<3); - bank->cnf[p] = __raw_readl(GPIO_CNF(gpio)); - bank->out[p] = __raw_readl(GPIO_OUT(gpio)); - bank->oe[p] = __raw_readl(GPIO_OE(gpio)); - bank->int_enb[p] = __raw_readl(GPIO_INT_ENB(gpio)); - bank->int_lvl[p] = __raw_readl(GPIO_INT_LVL(gpio)); - } - } - local_irq_restore(flags); -} - -static int tegra_gpio_wake_enable(struct irq_data *d, unsigned int enable) -{ - struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); - return irq_set_irq_wake(bank->irq, enable); -} -#endif - -static struct irq_chip tegra_gpio_irq_chip = { - .name = "GPIO", - .irq_ack = tegra_gpio_irq_ack, - .irq_mask = tegra_gpio_irq_mask, - .irq_unmask = tegra_gpio_irq_unmask, - .irq_set_type = tegra_gpio_irq_set_type, -#ifdef CONFIG_PM - .irq_set_wake = tegra_gpio_wake_enable, -#endif -}; - - -/* 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 __init tegra_gpio_init(void) -{ - struct tegra_gpio_bank *bank; - int i; - int j; - - for (i = 0; i < 7; i++) { - for (j = 0; j < 4; j++) { - int gpio = tegra_gpio_compose(i, j, 0); - __raw_writel(0x00, GPIO_INT_ENB(gpio)); - } - } - -#ifdef CONFIG_OF_GPIO - /* - * This isn't ideal, but it gets things hooked up until this - * driver is converted into a platform_device - */ - tegra_gpio_chip.of_node = of_find_compatible_node(NULL, NULL, - "nvidia,tegra20-gpio"); -#endif /* CONFIG_OF_GPIO */ - - gpiochip_add(&tegra_gpio_chip); - - for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) { - bank = &tegra_gpio_banks[GPIO_BANK(irq_to_gpio(i))]; - - irq_set_lockdep_class(i, &gpio_lock_class); - irq_set_chip_data(i, bank); - irq_set_chip_and_handler(i, &tegra_gpio_irq_chip, - handle_simple_irq); - set_irq_flags(i, IRQF_VALID); - } - - for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { - bank = &tegra_gpio_banks[i]; - - irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler); - irq_set_handler_data(bank->irq, bank); - - for (j = 0; j < 4; j++) - spin_lock_init(&bank->lvl_lock[j]); - } - - return 0; -} - -postcore_initcall(tegra_gpio_init); - -void __init tegra_gpio_config(struct tegra_gpio_table *table, int num) -{ - int i; - - for (i = 0; i < num; i++) { - int gpio = table[i].gpio; - - if (table[i].enable) - tegra_gpio_enable(gpio); - else - tegra_gpio_disable(gpio); - } -} - -#ifdef CONFIG_DEBUG_FS - -#include <linux/debugfs.h> -#include <linux/seq_file.h> - -static int dbg_gpio_show(struct seq_file *s, void *unused) -{ - int i; - int j; - - for (i = 0; i < 7; i++) { - for (j = 0; j < 4; j++) { - int gpio = tegra_gpio_compose(i, j, 0); - seq_printf(s, - "%d:%d %02x %02x %02x %02x %02x %02x %06x\n", - i, j, - __raw_readl(GPIO_CNF(gpio)), - __raw_readl(GPIO_OE(gpio)), - __raw_readl(GPIO_OUT(gpio)), - __raw_readl(GPIO_IN(gpio)), - __raw_readl(GPIO_INT_STA(gpio)), - __raw_readl(GPIO_INT_ENB(gpio)), - __raw_readl(GPIO_INT_LVL(gpio))); - } - } - return 0; -} - -static int dbg_gpio_open(struct inode *inode, struct file *file) -{ - return single_open(file, dbg_gpio_show, &inode->i_private); -} - -static const struct file_operations debug_fops = { - .open = dbg_gpio_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init tegra_gpio_debuginit(void) -{ - (void) debugfs_create_file("tegra_gpio", S_IRUGO, - NULL, NULL, &debug_fops); - return 0; -} -late_initcall(tegra_gpio_debuginit); -#endif diff --git a/drivers/gpio/gpio-u300.c b/drivers/gpio/gpio-u300.c index fd2dfeeefdf..d92790140fe 100644 --- a/drivers/gpio/gpio-u300.c +++ b/drivers/gpio/gpio-u300.c @@ -1,8 +1,11 @@ /* - * U300 GPIO module. + * + * arch/arm/mach-u300/gpio.c + * * * Copyright (C) 2007-2009 ST-Ericsson AB * License terms: GNU General Public License (GPL) version 2 + * U300 GPIO module. * This can driver either of the two basic GPIO cores * available in the U300 platforms: * COH 901 335 - Used in DB3150 (U300 1.0) and DB3200 (U330 1.0) diff --git a/drivers/gpio/gpio-it8761e.c b/drivers/gpio/it8761e_gpio.c index 278b8131701..48fc43c4bdd 100644 --- a/drivers/gpio/gpio-it8761e.c +++ b/drivers/gpio/it8761e_gpio.c @@ -1,5 +1,5 @@ /* - * GPIO interface for IT8761E Super I/O chip + * it8761_gpio.c - GPIO interface for IT8761E Super I/O chip * * Author: Denis Turischev <denis@compulab.co.il> * diff --git a/drivers/gpio/gpio-janz-ttl.c b/drivers/gpio/janz-ttl.c index 813ac077e5d..813ac077e5d 100644 --- a/drivers/gpio/gpio-janz-ttl.c +++ b/drivers/gpio/janz-ttl.c diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/langwell_gpio.c index d2eb57c60e0..644ba1255d3 100644 --- a/drivers/gpio/gpio-langwell.c +++ b/drivers/gpio/langwell_gpio.c @@ -1,6 +1,4 @@ -/* - * Moorestown platform Langwell chip GPIO driver - * +/* langwell_gpio.c Moorestown platform Langwell chip GPIO driver * Copyright (c) 2008 - 2009, Intel Corporation. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/gpio/gpio-max7300.c b/drivers/gpio/max7300.c index a5ca0ab1b37..962f661c18c 100644 --- a/drivers/gpio/gpio-max7300.c +++ b/drivers/gpio/max7300.c @@ -1,4 +1,6 @@ /* + * drivers/gpio/max7300.c + * * Copyright (C) 2009 Wolfram Sang, Pengutronix * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/gpio/gpio-max7301.c b/drivers/gpio/max7301.c index 741acfcbe76..92a100ddef6 100644 --- a/drivers/gpio/gpio-max7301.c +++ b/drivers/gpio/max7301.c @@ -1,4 +1,6 @@ /* + * drivers/gpio/max7301.c + * * Copyright (C) 2006 Juergen Beisert, Pengutronix * Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix * Copyright (C) 2009 Wolfram Sang, Pengutronix diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/max730x.c index 05e2dac60b3..94ce773f95f 100644 --- a/drivers/gpio/gpio-max730x.c +++ b/drivers/gpio/max730x.c @@ -1,4 +1,6 @@ /** + * drivers/gpio/max7301.c + * * Copyright (C) 2006 Juergen Beisert, Pengutronix * Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix * Copyright (C) 2009 Wolfram Sang, Pengutronix diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/max732x.c index 9504120812a..ad6951edc16 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/max732x.c @@ -1,5 +1,5 @@ /* - * MAX732x I2C Port Expander with 8/16 I/O + * max732x.c - I2C Port Expander with 8/16 I/O * * Copyright (C) 2007 Marvell International Ltd. * Copyright (C) 2008 Jack Ren <jack.ren@marvell.com> diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/mc33880.c index b3b4652e89e..4ec797593bd 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/mc33880.c @@ -1,5 +1,5 @@ /* - * MC33880 high-side/low-side switch GPIO driver + * mc33880.c MC33880 high-side/low-side switch GPIO driver * Copyright (c) 2009 Intel Corporation * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/mcp23s08.c index 1ef46e6c2a2..40e076083ec 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/mcp23s08.c @@ -1,12 +1,12 @@ /* - * MCP23S08 SPI/GPIO gpio expander driver + * mcp23s08.c - SPI gpio expander driver */ #include <linux/kernel.h> #include <linux/device.h> +#include <linux/workqueue.h> #include <linux/mutex.h> #include <linux/gpio.h> -#include <linux/i2c.h> #include <linux/spi/spi.h> #include <linux/spi/mcp23s08.h> #include <linux/slab.h> @@ -17,13 +17,13 @@ */ #define MCP_TYPE_S08 0 #define MCP_TYPE_S17 1 -#define MCP_TYPE_008 2 -#define MCP_TYPE_017 3 /* Registers are all 8 bits wide. * * The mcp23s17 has twice as many bits, and can be configured to work * with either 16 bit registers or with two adjacent 8 bit banks. + * + * Also, there are I2C versions of both chips. */ #define MCP_IODIR 0x00 /* init/reset: all ones */ #define MCP_IPOL 0x01 @@ -51,6 +51,7 @@ struct mcp23s08_ops { }; struct mcp23s08 { + struct spi_device *spi; u8 addr; u16 cache[11]; @@ -59,8 +60,9 @@ struct mcp23s08 { struct gpio_chip chip; + struct work_struct work; + const struct mcp23s08_ops *ops; - void *data; /* ops specific data */ }; /* A given spi_device can represent up to eight mcp23sxx chips @@ -74,74 +76,6 @@ struct mcp23s08_driver_data { struct mcp23s08 chip[]; }; -/*----------------------------------------------------------------------*/ - -#ifdef CONFIG_I2C - -static int mcp23008_read(struct mcp23s08 *mcp, unsigned reg) -{ - return i2c_smbus_read_byte_data(mcp->data, reg); -} - -static int mcp23008_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) -{ - return i2c_smbus_write_byte_data(mcp->data, reg, val); -} - -static int -mcp23008_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) -{ - while (n--) { - int ret = mcp23008_read(mcp, reg++); - if (ret < 0) - return ret; - *vals++ = ret; - } - - return 0; -} - -static int mcp23017_read(struct mcp23s08 *mcp, unsigned reg) -{ - return i2c_smbus_read_word_data(mcp->data, reg << 1); -} - -static int mcp23017_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) -{ - return i2c_smbus_write_word_data(mcp->data, reg << 1, val); -} - -static int -mcp23017_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) -{ - while (n--) { - int ret = mcp23017_read(mcp, reg++); - if (ret < 0) - return ret; - *vals++ = ret; - } - - return 0; -} - -static const struct mcp23s08_ops mcp23008_ops = { - .read = mcp23008_read, - .write = mcp23008_write, - .read_regs = mcp23008_read_regs, -}; - -static const struct mcp23s08_ops mcp23017_ops = { - .read = mcp23017_read, - .write = mcp23017_write, - .read_regs = mcp23017_read_regs, -}; - -#endif /* CONFIG_I2C */ - -/*----------------------------------------------------------------------*/ - -#ifdef CONFIG_SPI_MASTER - static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg) { u8 tx[2], rx[1]; @@ -149,7 +83,7 @@ static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg) tx[0] = mcp->addr | 0x01; tx[1] = reg; - status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx); + status = spi_write_then_read(mcp->spi, tx, sizeof tx, rx, sizeof rx); return (status < 0) ? status : rx[0]; } @@ -160,7 +94,7 @@ static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) tx[0] = mcp->addr; tx[1] = reg; tx[2] = val; - return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0); + return spi_write_then_read(mcp->spi, tx, sizeof tx, NULL, 0); } static int @@ -175,7 +109,7 @@ mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) tx[1] = reg; tmp = (u8 *)vals; - status = spi_write_then_read(mcp->data, tx, sizeof tx, tmp, n); + status = spi_write_then_read(mcp->spi, tx, sizeof tx, tmp, n); if (status >= 0) { while (n--) vals[n] = tmp[n]; /* expand to 16bit */ @@ -190,7 +124,7 @@ static int mcp23s17_read(struct mcp23s08 *mcp, unsigned reg) tx[0] = mcp->addr | 0x01; tx[1] = reg << 1; - status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx); + status = spi_write_then_read(mcp->spi, tx, sizeof tx, rx, sizeof rx); return (status < 0) ? status : (rx[0] | (rx[1] << 8)); } @@ -202,7 +136,7 @@ static int mcp23s17_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) tx[1] = reg << 1; tx[2] = val; tx[3] = val >> 8; - return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0); + return spi_write_then_read(mcp->spi, tx, sizeof tx, NULL, 0); } static int @@ -216,7 +150,7 @@ mcp23s17_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) tx[0] = mcp->addr | 0x01; tx[1] = reg << 1; - status = spi_write_then_read(mcp->data, tx, sizeof tx, + status = spi_write_then_read(mcp->spi, tx, sizeof tx, (u8 *)vals, n * 2); if (status >= 0) { while (n--) @@ -238,7 +172,6 @@ static const struct mcp23s08_ops mcp23s17_ops = { .read_regs = mcp23s17_read_regs, }; -#endif /* CONFIG_SPI_MASTER */ /*----------------------------------------------------------------------*/ @@ -366,16 +299,17 @@ done: /*----------------------------------------------------------------------*/ -static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, - void *data, unsigned addr, +static int mcp23s08_probe_one(struct spi_device *spi, unsigned addr, unsigned type, unsigned base, unsigned pullups) { - int status; + struct mcp23s08_driver_data *data = spi_get_drvdata(spi); + struct mcp23s08 *mcp = data->mcp[addr]; + int status; mutex_init(&mcp->lock); - mcp->data = data; - mcp->addr = addr; + mcp->spi = spi; + mcp->addr = 0x40 | (addr << 1); mcp->chip.direction_input = mcp23s08_direction_input; mcp->chip.get = mcp23s08_get; @@ -383,43 +317,18 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, mcp->chip.set = mcp23s08_set; mcp->chip.dbg_show = mcp23s08_dbg_show; - switch (type) { -#ifdef CONFIG_SPI_MASTER - case MCP_TYPE_S08: - mcp->ops = &mcp23s08_ops; - mcp->chip.ngpio = 8; - mcp->chip.label = "mcp23s08"; - break; - - case MCP_TYPE_S17: + if (type == MCP_TYPE_S17) { mcp->ops = &mcp23s17_ops; mcp->chip.ngpio = 16; mcp->chip.label = "mcp23s17"; - break; -#endif /* CONFIG_SPI_MASTER */ - -#ifdef CONFIG_I2C - case MCP_TYPE_008: - mcp->ops = &mcp23008_ops; + } else { + mcp->ops = &mcp23s08_ops; mcp->chip.ngpio = 8; - mcp->chip.label = "mcp23008"; - break; - - case MCP_TYPE_017: - mcp->ops = &mcp23017_ops; - mcp->chip.ngpio = 16; - mcp->chip.label = "mcp23017"; - break; -#endif /* CONFIG_I2C */ - - default: - dev_err(dev, "invalid device type (%d)\n", type); - return -EINVAL; + mcp->chip.label = "mcp23s08"; } - mcp->chip.base = base; mcp->chip.can_sleep = 1; - mcp->chip.dev = dev; + mcp->chip.dev = &spi->dev; mcp->chip.owner = THIS_MODULE; /* verify MCP_IOCON.SEQOP = 0, so sequential reads work, @@ -465,98 +374,11 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, status = gpiochip_add(&mcp->chip); fail: if (status < 0) - dev_dbg(dev, "can't setup chip %d, --> %d\n", - addr, status); + dev_dbg(&spi->dev, "can't setup chip %d, --> %d\n", + addr, status); return status; } -/*----------------------------------------------------------------------*/ - -#ifdef CONFIG_I2C - -static int __devinit mcp230xx_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct mcp23s08_platform_data *pdata; - struct mcp23s08 *mcp; - int status; - - pdata = client->dev.platform_data; - if (!pdata || !gpio_is_valid(pdata->base)) { - dev_dbg(&client->dev, "invalid or missing platform data\n"); - return -EINVAL; - } - - mcp = kzalloc(sizeof *mcp, GFP_KERNEL); - if (!mcp) - return -ENOMEM; - - status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr, - id->driver_data, pdata->base, - pdata->chip[0].pullups); - if (status) - goto fail; - - i2c_set_clientdata(client, mcp); - - return 0; - -fail: - kfree(mcp); - - return status; -} - -static int __devexit mcp230xx_remove(struct i2c_client *client) -{ - struct mcp23s08 *mcp = i2c_get_clientdata(client); - int status; - - status = gpiochip_remove(&mcp->chip); - if (status == 0) - kfree(mcp); - - return status; -} - -static const struct i2c_device_id mcp230xx_id[] = { - { "mcp23008", MCP_TYPE_008 }, - { "mcp23017", MCP_TYPE_017 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, mcp230xx_id); - -static struct i2c_driver mcp230xx_driver = { - .driver = { - .name = "mcp230xx", - .owner = THIS_MODULE, - }, - .probe = mcp230xx_probe, - .remove = __devexit_p(mcp230xx_remove), - .id_table = mcp230xx_id, -}; - -static int __init mcp23s08_i2c_init(void) -{ - return i2c_add_driver(&mcp230xx_driver); -} - -static void mcp23s08_i2c_exit(void) -{ - i2c_del_driver(&mcp230xx_driver); -} - -#else - -static int __init mcp23s08_i2c_init(void) { return 0; } -static void mcp23s08_i2c_exit(void) { } - -#endif /* CONFIG_I2C */ - -/*----------------------------------------------------------------------*/ - -#ifdef CONFIG_SPI_MASTER - static int mcp23s08_probe(struct spi_device *spi) { struct mcp23s08_platform_data *pdata; @@ -599,8 +421,7 @@ static int mcp23s08_probe(struct spi_device *spi) continue; chips--; data->mcp[addr] = &data->chip[chips]; - status = mcp23s08_probe_one(data->mcp[addr], &spi->dev, spi, - 0x40 | (addr << 1), type, base, + status = mcp23s08_probe_one(spi, addr, type, base, pdata->chip[addr].pullups); if (status < 0) goto fail; @@ -614,6 +435,14 @@ static int mcp23s08_probe(struct spi_device *spi) * handled here... */ + if (pdata->setup) { + status = pdata->setup(spi, + pdata->base, data->ngpio, + pdata->context); + if (status < 0) + dev_dbg(&spi->dev, "setup --> %d\n", status); + } + return 0; fail: @@ -633,9 +462,20 @@ fail: static int mcp23s08_remove(struct spi_device *spi) { struct mcp23s08_driver_data *data = spi_get_drvdata(spi); + struct mcp23s08_platform_data *pdata = spi->dev.platform_data; unsigned addr; int status = 0; + if (pdata->teardown) { + status = pdata->teardown(spi, + pdata->base, data->ngpio, + pdata->context); + if (status < 0) { + dev_err(&spi->dev, "%s --> %d\n", "teardown", status); + return status; + } + } + for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) { int tmp; @@ -670,53 +510,20 @@ static struct spi_driver mcp23s08_driver = { }, }; -static int __init mcp23s08_spi_init(void) -{ - return spi_register_driver(&mcp23s08_driver); -} - -static void mcp23s08_spi_exit(void) -{ - spi_unregister_driver(&mcp23s08_driver); -} - -#else - -static int __init mcp23s08_spi_init(void) { return 0; } -static void mcp23s08_spi_exit(void) { } - -#endif /* CONFIG_SPI_MASTER */ - /*----------------------------------------------------------------------*/ static int __init mcp23s08_init(void) { - int ret; - - ret = mcp23s08_spi_init(); - if (ret) - goto spi_fail; - - ret = mcp23s08_i2c_init(); - if (ret) - goto i2c_fail; - - return 0; - - i2c_fail: - mcp23s08_spi_exit(); - spi_fail: - return ret; + return spi_register_driver(&mcp23s08_driver); } -/* register after spi/i2c postcore initcall and before +/* register after spi postcore initcall and before * subsys initcalls that may rely on these GPIOs */ subsys_initcall(mcp23s08_init); static void __exit mcp23s08_exit(void) { - mcp23s08_spi_exit(); - mcp23s08_i2c_exit(); + spi_unregister_driver(&mcp23s08_driver); } module_exit(mcp23s08_exit); diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/ml_ioh_gpio.c index a9016f56ed7..1bc621ac353 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/ml_ioh_gpio.c @@ -233,7 +233,7 @@ static int __devinit ioh_gpio_probe(struct pci_dev *pdev, return 0; err_gpiochip_add: - while (--i >= 0) { + for (; i != 0; i--) { chip--; ret = gpiochip_remove(&chip->gpio); if (ret) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/pca953x.c index c43b8ff626a..0451d7ac94a 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/pca953x.c @@ -1,5 +1,5 @@ /* - * PCA953x 4/8/16 bit I/O ports + * pca953x.c - 4/8/16 bit I/O ports * * Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com> * Copyright (C) 2007 Marvell International Ltd. @@ -21,6 +21,7 @@ #include <linux/slab.h> #ifdef CONFIG_OF_GPIO #include <linux/of_platform.h> +#include <linux/of_gpio.h> #endif #define PCA953X_INPUT 0 @@ -84,6 +85,7 @@ struct pca953x_chip { #endif struct i2c_client *client; + struct pca953x_platform_data *dyn_pdata; struct gpio_chip gpio_chip; const char *const *names; int chip_type; @@ -435,7 +437,7 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid) do { level = __ffs(pending); - handle_nested_irq(level + chip->irq_base); + generic_handle_irq(level + chip->irq_base); pending &= ~(1 << level); } while (pending); @@ -444,13 +446,13 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid) } static int pca953x_irq_setup(struct pca953x_chip *chip, - const struct i2c_device_id *id, - int irq_base) + const struct i2c_device_id *id) { struct i2c_client *client = chip->client; + struct pca953x_platform_data *pdata = client->dev.platform_data; int ret, offset = 0; - if (irq_base != -1 + if (pdata->irq_base != -1 && (id->driver_data & PCA_INT)) { int lvl; @@ -472,19 +474,15 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, * this purpose. */ chip->irq_stat &= chip->reg_direction; + chip->irq_base = pdata->irq_base; mutex_init(&chip->irq_lock); - chip->irq_base = irq_alloc_descs(-1, irq_base, chip->gpio_chip.ngpio, -1); - if (chip->irq_base < 0) - goto out_failed; - for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) { int irq = lvl + chip->irq_base; - irq_clear_status_flags(irq, IRQ_NOREQUEST); irq_set_chip_data(irq, chip); - irq_set_chip(irq, &pca953x_irq_chip); - irq_set_nested_thread(irq, true); + irq_set_chip_and_handler(irq, &pca953x_irq_chip, + handle_simple_irq); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else @@ -495,7 +493,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ret = request_threaded_irq(client->irq, NULL, pca953x_irq_handler, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, dev_name(&client->dev), chip); if (ret) { dev_err(&client->dev, "failed to request irq %d\n", @@ -515,19 +514,17 @@ out_failed: static void pca953x_irq_teardown(struct pca953x_chip *chip) { - if (chip->irq_base != -1) { - irq_free_descs(chip->irq_base, chip->gpio_chip.ngpio); + if (chip->irq_base != -1) free_irq(chip->client->irq, chip); - } } #else /* CONFIG_GPIO_PCA953X_IRQ */ static int pca953x_irq_setup(struct pca953x_chip *chip, - const struct i2c_device_id *id, - int irq_base) + const struct i2c_device_id *id) { struct i2c_client *client = chip->client; + struct pca953x_platform_data *pdata = client->dev.platform_data; - if (irq_base != -1 && (id->driver_data & PCA_INT)) + if (pdata->irq_base != -1 && (id->driver_data & PCA_INT)) dev_warn(&client->dev, "interrupt support not compiled in\n"); return 0; @@ -544,39 +541,46 @@ static void pca953x_irq_teardown(struct pca953x_chip *chip) #ifdef CONFIG_OF_GPIO /* * Translate OpenFirmware node properties into platform_data - * WARNING: This is DEPRECATED and will be removed eventually! */ -void -pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, int *invert) +static struct pca953x_platform_data * +pca953x_get_alt_pdata(struct i2c_client *client) { + struct pca953x_platform_data *pdata; struct device_node *node; const __be32 *val; int size; node = client->dev.of_node; if (node == NULL) - return; + return NULL; + + pdata = kzalloc(sizeof(struct pca953x_platform_data), GFP_KERNEL); + if (pdata == NULL) { + dev_err(&client->dev, "Unable to allocate platform_data\n"); + return NULL; + } - *gpio_base = -1; + pdata->gpio_base = -1; val = of_get_property(node, "linux,gpio-base", &size); - WARN(val, "%s: device-tree property 'linux,gpio-base' is deprecated!", __func__); if (val) { if (size != sizeof(*val)) dev_warn(&client->dev, "%s: wrong linux,gpio-base\n", node->full_name); else - *gpio_base = be32_to_cpup(val); + pdata->gpio_base = be32_to_cpup(val); } val = of_get_property(node, "polarity", NULL); - WARN(val, "%s: device-tree property 'polarity' is deprecated!", __func__); if (val) - *invert = *val; + pdata->invert = *val; + + return pdata; } #else -void -pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, int *invert) +static struct pca953x_platform_data * +pca953x_get_alt_pdata(struct i2c_client *client) { + return NULL; } #endif @@ -638,7 +642,6 @@ static int __devinit pca953x_probe(struct i2c_client *client, { struct pca953x_platform_data *pdata; struct pca953x_chip *chip; - int irq_base=0, invert=0; int ret = 0; chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL); @@ -646,22 +649,26 @@ static int __devinit pca953x_probe(struct i2c_client *client, return -ENOMEM; pdata = client->dev.platform_data; - if (pdata) { - irq_base = pdata->irq_base; - chip->gpio_start = pdata->gpio_base; - invert = pdata->invert; - chip->names = pdata->names; - } else { - pca953x_get_alt_pdata(client, &chip->gpio_start, &invert); -#ifdef CONFIG_OF_GPIO - /* If I2C node has no interrupts property, disable GPIO interrupts */ - if (of_find_property(client->dev.of_node, "interrupts", NULL) == NULL) - irq_base = -1; -#endif + if (pdata == NULL) { + pdata = pca953x_get_alt_pdata(client); + /* + * Unlike normal platform_data, this is allocated + * dynamically and must be freed in the driver + */ + chip->dyn_pdata = pdata; + } + + if (pdata == NULL) { + dev_dbg(&client->dev, "no platform data\n"); + ret = -EINVAL; + goto out_failed; } chip->client = client; + chip->gpio_start = pdata->gpio_base; + + chip->names = pdata->names; chip->chip_type = id->driver_data & (PCA953X_TYPE | PCA957X_TYPE); mutex_init(&chip->i2c_lock); @@ -672,13 +679,13 @@ static int __devinit pca953x_probe(struct i2c_client *client, pca953x_setup_gpio(chip, id->driver_data & PCA_GPIO_MASK); if (chip->chip_type == PCA953X_TYPE) - device_pca953x_init(chip, invert); + device_pca953x_init(chip, pdata->invert); else if (chip->chip_type == PCA957X_TYPE) - device_pca957x_init(chip, invert); + device_pca957x_init(chip, pdata->invert); else goto out_failed; - ret = pca953x_irq_setup(chip, id, irq_base); + ret = pca953x_irq_setup(chip, id); if (ret) goto out_failed; @@ -686,7 +693,7 @@ static int __devinit pca953x_probe(struct i2c_client *client, if (ret) goto out_failed_irq; - if (pdata && pdata->setup) { + if (pdata->setup) { ret = pdata->setup(client, chip->gpio_chip.base, chip->gpio_chip.ngpio, pdata->context); if (ret < 0) @@ -699,6 +706,7 @@ static int __devinit pca953x_probe(struct i2c_client *client, out_failed_irq: pca953x_irq_teardown(chip); out_failed: + kfree(chip->dyn_pdata); kfree(chip); return ret; } @@ -709,7 +717,7 @@ static int pca953x_remove(struct i2c_client *client) struct pca953x_chip *chip = i2c_get_clientdata(client); int ret = 0; - if (pdata && pdata->teardown) { + if (pdata->teardown) { ret = pdata->teardown(client, chip->gpio_chip.base, chip->gpio_chip.ngpio, pdata->context); if (ret < 0) { @@ -727,6 +735,7 @@ static int pca953x_remove(struct i2c_client *client) } pca953x_irq_teardown(chip); + kfree(chip->dyn_pdata); kfree(chip); return 0; } diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/pcf857x.c index 7369fdda92b..879b473aab5 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/pcf857x.c @@ -1,5 +1,5 @@ /* - * Driver for pcf857x, pca857x, and pca967x I2C GPIO expanders + * pcf857x - driver for pcf857x, pca857x, and pca967x I2C GPIO expanders * * Copyright (C) 2007 David Brownell * diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/pch_gpio.c index 36919e77c49..36919e77c49 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/pch_gpio.c diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/pl061.c index 2c5a18f32bf..6fcb28cdd86 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/pl061.c @@ -1,5 +1,7 @@ /* - * Copyright (C) 2008, 2009 Provigent Ltd. + * linux/drivers/gpio/pl061.c + * + * Copyright (C) 2008, 2009 Provigent Ltd. * * 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 diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/rdc321x-gpio.c index 2762698e020..2762698e020 100644 --- a/drivers/gpio/gpio-rdc321x.c +++ b/drivers/gpio/rdc321x-gpio.c diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/sch_gpio.c index 16351584549..56060421cdf 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/sch_gpio.c @@ -1,5 +1,5 @@ /* - * GPIO interface for Intel Poulsbo SCH + * sch_gpio.c - GPIO interface for Intel Poulsbo SCH * * Copyright (c) 2010 CompuLab Ltd * Author: Denis Turischev <denis@compulab.co.il> diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/stmpe-gpio.c index 4c980b57332..4c980b57332 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/stmpe-gpio.c diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/sx150x.c index a4f73534394..a4f73534394 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/sx150x.c diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/tc3589x-gpio.c index 2a82e8999a4..2a82e8999a4 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/tc3589x-gpio.c diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/timbgpio.c index c593bd46bfb..0265872e57d 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/timbgpio.c @@ -1,5 +1,5 @@ /* - * Timberdale FPGA GPIO driver + * timbgpio.c timberdale FPGA GPIO driver * Copyright (c) 2009 Intel Corporation * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/tps65910-gpio.c index b9c1c297669..15097ca616d 100644 --- a/drivers/gpio/gpio-tps65910.c +++ b/drivers/gpio/tps65910-gpio.c @@ -1,5 +1,5 @@ /* - * TI TPS6591x GPIO driver + * tps65910-gpio.c -- TI TPS6591x * * Copyright 2010 Texas Instruments Inc. * diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/twl4030-gpio.c index b8b4f228757..57635ac35a7 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/twl4030-gpio.c @@ -1,5 +1,5 @@ /* - * Access to GPIOs on TWL4030/TPS659x0 chips + * twl4030_gpio.c -- access to GPIOs on TWL4030/TPS659x0 chips * * Copyright (C) 2006-2007 Texas Instruments, Inc. * Copyright (C) 2006 MontaVista Software, Inc. diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/ucb1400_gpio.c index 50e6bd1392c..50e6bd1392c 100644 --- a/drivers/gpio/gpio-ucb1400.c +++ b/drivers/gpio/ucb1400_gpio.c diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/vr41xx_giu.c index 98723cb9ac6..a365be040b3 100644 --- a/drivers/gpio/gpio-vr41xx.c +++ b/drivers/gpio/vr41xx_giu.c @@ -518,7 +518,7 @@ static int __devinit giu_probe(struct platform_device *pdev) if (!res) return -EBUSY; - giu_base = ioremap(res->start, resource_size(res)); + giu_base = ioremap(res->start, res->end - res->start + 1); if (!giu_base) return -ENOMEM; diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/vx855_gpio.c index ef5aabd8b8b..ef5aabd8b8b 100644 --- a/drivers/gpio/gpio-vx855.c +++ b/drivers/gpio/vx855_gpio.c diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/wm831x-gpio.c index deb949e75ec..2bcfb0be09f 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/wm831x-gpio.c @@ -1,5 +1,5 @@ /* - * gpiolib support for Wolfson WM831x PMICs + * wm831x-gpio.c -- gpiolib support for Wolfson WM831x PMICs * * Copyright 2009 Wolfson Microelectronics PLC. * diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/wm8350-gpiolib.c index a06af515483..359999290f5 100644 --- a/drivers/gpio/gpio-wm8350.c +++ b/drivers/gpio/wm8350-gpiolib.c @@ -1,5 +1,5 @@ /* - * gpiolib support for Wolfson WM835x PMICs + * wm835x-gpiolib.c -- gpiolib support for Wolfson WM835x PMICs * * Copyright 2009 Wolfson Microelectronics PLC. * diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/wm8994-gpio.c index 96198f3fab7..c822baacd8f 100644 --- a/drivers/gpio/gpio-wm8994.c +++ b/drivers/gpio/wm8994-gpio.c @@ -1,5 +1,5 @@ /* - * gpiolib support for Wolfson WM8994 + * wm8994-gpio.c -- gpiolib support for Wolfson WM8994 * * Copyright 2009 Wolfson Microelectronics PLC. * diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/xilinx_gpio.c index 846fbd5e31b..846fbd5e31b 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/xilinx_gpio.c diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index d1bf8724b58..45dc6aa62ba 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -267,7 +267,7 @@ config INPUT_TWL4030_PWRBUTTON config INPUT_TWL4030_VIBRA tristate "Support for TWL4030 Vibrator" depends on TWL4030_CORE - select MFD_TWL4030_AUDIO + select TWL4030_CODEC select INPUT_FF_MEMLESS help This option enables support for TWL4030 Vibrator Driver. @@ -275,17 +275,6 @@ config INPUT_TWL4030_VIBRA To compile this driver as a module, choose M here. The module will be called twl4030_vibra. -config INPUT_TWL6040_VIBRA - tristate "Support for TWL6040 Vibrator" - depends on TWL4030_CORE - select TWL6040_CORE - select INPUT_FF_MEMLESS - help - This option enables support for TWL6040 Vibrator Driver. - - To compile this driver as a module, choose M here. The module will - be called twl6040_vibra. - config INPUT_UINPUT tristate "User level driver support" help diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 4da7c3a60e0..38efb2cb182 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -40,7 +40,6 @@ obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o -obj-$(CONFIG_INPUT_TWL6040_VIBRA) += twl6040-vibra.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index 3c1a432c14d..014dd4ad0d4 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -28,7 +28,7 @@ #include <linux/platform_device.h> #include <linux/workqueue.h> #include <linux/i2c/twl.h> -#include <linux/mfd/twl4030-audio.h> +#include <linux/mfd/twl4030-codec.h> #include <linux/input.h> #include <linux/slab.h> @@ -67,7 +67,7 @@ static void vibra_enable(struct vibra_info *info) { u8 reg; - twl4030_audio_enable_resource(TWL4030_AUDIO_RES_POWER); + twl4030_codec_enable_resource(TWL4030_CODEC_RES_POWER); /* turn H-Bridge on */ twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, @@ -75,7 +75,7 @@ static void vibra_enable(struct vibra_info *info) twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, (reg | TWL4030_VIBRA_EN), TWL4030_REG_VIBRA_CTL); - twl4030_audio_enable_resource(TWL4030_AUDIO_RES_APLL); + twl4030_codec_enable_resource(TWL4030_CODEC_RES_APLL); info->enabled = true; } @@ -90,8 +90,8 @@ static void vibra_disable(struct vibra_info *info) twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, (reg & ~TWL4030_VIBRA_EN), TWL4030_REG_VIBRA_CTL); - twl4030_audio_disable_resource(TWL4030_AUDIO_RES_APLL); - twl4030_audio_disable_resource(TWL4030_AUDIO_RES_POWER); + twl4030_codec_disable_resource(TWL4030_CODEC_RES_APLL); + twl4030_codec_disable_resource(TWL4030_CODEC_RES_POWER); info->enabled = false; } @@ -196,7 +196,7 @@ static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops, static int __devinit twl4030_vibra_probe(struct platform_device *pdev) { - struct twl4030_vibra_data *pdata = pdev->dev.platform_data; + struct twl4030_codec_vibra_data *pdata = pdev->dev.platform_data; struct vibra_info *info; int ret; diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c deleted file mode 100644 index c43002e7ec7..00000000000 --- a/drivers/input/misc/twl6040-vibra.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - * twl6040-vibra.c - TWL6040 Vibrator driver - * - * Author: Jorge Eduardo Candelaria <jorge.candelaria@ti.com> - * Author: Misael Lopez Cruz <misael.lopez@ti.com> - * - * Copyright: (C) 2011 Texas Instruments, Inc. - * - * Based on twl4030-vibra.c by Henrik Saari <henrik.saari@nokia.com> - * Felipe Balbi <felipe.balbi@nokia.com> - * Jari Vanhala <ext-javi.vanhala@nokia.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/module.h> -#include <linux/platform_device.h> -#include <linux/workqueue.h> -#include <linux/i2c/twl.h> -#include <linux/mfd/twl6040.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/regulator/consumer.h> - -#define EFFECT_DIR_180_DEG 0x8000 - -/* Recommended modulation index 85% */ -#define TWL6040_VIBRA_MOD 85 - -#define TWL6040_NUM_SUPPLIES 2 - -struct vibra_info { - struct device *dev; - struct input_dev *input_dev; - struct workqueue_struct *workqueue; - struct work_struct play_work; - struct mutex mutex; - int irq; - - bool enabled; - int weak_speed; - int strong_speed; - int direction; - - unsigned int vibldrv_res; - unsigned int vibrdrv_res; - unsigned int viblmotor_res; - unsigned int vibrmotor_res; - - struct regulator_bulk_data supplies[TWL6040_NUM_SUPPLIES]; - - struct twl6040 *twl6040; -}; - -static irqreturn_t twl6040_vib_irq_handler(int irq, void *data) -{ - struct vibra_info *info = data; - struct twl6040 *twl6040 = info->twl6040; - u8 status; - - status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS); - if (status & TWL6040_VIBLOCDET) { - dev_warn(info->dev, "Left Vibrator overcurrent detected\n"); - twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL, - TWL6040_VIBENAL); - } - if (status & TWL6040_VIBROCDET) { - dev_warn(info->dev, "Right Vibrator overcurrent detected\n"); - twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR, - TWL6040_VIBENAR); - } - - return IRQ_HANDLED; -} - -static void twl6040_vibra_enable(struct vibra_info *info) -{ - struct twl6040 *twl6040 = info->twl6040; - int ret; - - ret = regulator_bulk_enable(ARRAY_SIZE(info->supplies), info->supplies); - if (ret) { - dev_err(info->dev, "failed to enable regulators %d\n", ret); - return; - } - - twl6040_power(info->twl6040, 1); - if (twl6040->rev <= TWL6040_REV_ES1_1) { - /* - * ERRATA: Disable overcurrent protection for at least - * 3ms when enabling vibrator drivers to avoid false - * overcurrent detection - */ - twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, - TWL6040_VIBENAL | TWL6040_VIBCTRLL); - twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, - TWL6040_VIBENAR | TWL6040_VIBCTRLR); - usleep_range(3000, 3500); - } - - twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, - TWL6040_VIBENAL); - twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, - TWL6040_VIBENAR); - - info->enabled = true; -} - -static void twl6040_vibra_disable(struct vibra_info *info) -{ - struct twl6040 *twl6040 = info->twl6040; - - twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, 0x00); - twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, 0x00); - twl6040_power(info->twl6040, 0); - - regulator_bulk_disable(ARRAY_SIZE(info->supplies), info->supplies); - - info->enabled = false; -} - -static u8 twl6040_vibra_code(int vddvib, int vibdrv_res, int motor_res, - int speed, int direction) -{ - int vpk, max_code; - u8 vibdat; - - /* output swing */ - vpk = (vddvib * motor_res * TWL6040_VIBRA_MOD) / - (100 * (vibdrv_res + motor_res)); - - /* 50mV per VIBDAT code step */ - max_code = vpk / 50; - if (max_code > TWL6040_VIBDAT_MAX) - max_code = TWL6040_VIBDAT_MAX; - - /* scale speed to max allowed code */ - vibdat = (u8)((speed * max_code) / USHRT_MAX); - - /* 2's complement for direction > 180 degrees */ - vibdat *= direction; - - return vibdat; -} - -static void twl6040_vibra_set_effect(struct vibra_info *info) -{ - struct twl6040 *twl6040 = info->twl6040; - u8 vibdatl, vibdatr; - int volt; - - /* weak motor */ - volt = regulator_get_voltage(info->supplies[0].consumer) / 1000; - vibdatl = twl6040_vibra_code(volt, info->vibldrv_res, - info->viblmotor_res, - info->weak_speed, info->direction); - - /* strong motor */ - volt = regulator_get_voltage(info->supplies[1].consumer) / 1000; - vibdatr = twl6040_vibra_code(volt, info->vibrdrv_res, - info->vibrmotor_res, - info->strong_speed, info->direction); - - twl6040_reg_write(twl6040, TWL6040_REG_VIBDATL, vibdatl); - twl6040_reg_write(twl6040, TWL6040_REG_VIBDATR, vibdatr); -} - -static void vibra_play_work(struct work_struct *work) -{ - struct vibra_info *info = container_of(work, - struct vibra_info, play_work); - - mutex_lock(&info->mutex); - - if (info->weak_speed || info->strong_speed) { - if (!info->enabled) - twl6040_vibra_enable(info); - - twl6040_vibra_set_effect(info); - } else if (info->enabled) - twl6040_vibra_disable(info); - - mutex_unlock(&info->mutex); -} - -static int vibra_play(struct input_dev *input, void *data, - struct ff_effect *effect) -{ - struct vibra_info *info = input_get_drvdata(input); - int ret; - - info->weak_speed = effect->u.rumble.weak_magnitude; - info->strong_speed = effect->u.rumble.strong_magnitude; - info->direction = effect->direction < EFFECT_DIR_180_DEG ? 1 : -1; - - ret = queue_work(info->workqueue, &info->play_work); - if (!ret) { - dev_info(&input->dev, "work is already on queue\n"); - return ret; - } - - return 0; -} - -static void twl6040_vibra_close(struct input_dev *input) -{ - struct vibra_info *info = input_get_drvdata(input); - - cancel_work_sync(&info->play_work); - - mutex_lock(&info->mutex); - - if (info->enabled) - twl6040_vibra_disable(info); - - mutex_unlock(&info->mutex); -} - -#if CONFIG_PM_SLEEP -static int twl6040_vibra_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct vibra_info *info = platform_get_drvdata(pdev); - - mutex_lock(&info->mutex); - - if (info->enabled) - twl6040_vibra_disable(info); - - mutex_unlock(&info->mutex); - - return 0; -} - -#endif - -static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL); - -static int __devinit twl6040_vibra_probe(struct platform_device *pdev) -{ - struct twl4030_vibra_data *pdata = pdev->dev.platform_data; - struct vibra_info *info; - int ret; - - if (!pdata) { - dev_err(&pdev->dev, "platform_data not available\n"); - return -EINVAL; - } - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) { - dev_err(&pdev->dev, "couldn't allocate memory\n"); - return -ENOMEM; - } - - info->dev = &pdev->dev; - info->twl6040 = dev_get_drvdata(pdev->dev.parent); - info->vibldrv_res = pdata->vibldrv_res; - info->vibrdrv_res = pdata->vibrdrv_res; - info->viblmotor_res = pdata->viblmotor_res; - info->vibrmotor_res = pdata->vibrmotor_res; - if ((!info->vibldrv_res && !info->viblmotor_res) || - (!info->vibrdrv_res && !info->vibrmotor_res)) { - dev_err(info->dev, "invalid vibra driver/motor resistance\n"); - ret = -EINVAL; - goto err_kzalloc; - } - - info->irq = platform_get_irq(pdev, 0); - if (info->irq < 0) { - dev_err(info->dev, "invalid irq\n"); - ret = -EINVAL; - goto err_kzalloc; - } - - mutex_init(&info->mutex); - - info->input_dev = input_allocate_device(); - if (info->input_dev == NULL) { - dev_err(info->dev, "couldn't allocate input device\n"); - ret = -ENOMEM; - goto err_kzalloc; - } - - input_set_drvdata(info->input_dev, info); - - info->input_dev->name = "twl6040:vibrator"; - info->input_dev->id.version = 1; - info->input_dev->dev.parent = pdev->dev.parent; - info->input_dev->close = twl6040_vibra_close; - __set_bit(FF_RUMBLE, info->input_dev->ffbit); - - ret = input_ff_create_memless(info->input_dev, NULL, vibra_play); - if (ret < 0) { - dev_err(info->dev, "couldn't register vibrator to FF\n"); - goto err_ialloc; - } - - ret = input_register_device(info->input_dev); - if (ret < 0) { - dev_err(info->dev, "couldn't register input device\n"); - goto err_iff; - } - - platform_set_drvdata(pdev, info); - - ret = request_threaded_irq(info->irq, NULL, twl6040_vib_irq_handler, 0, - "twl6040_irq_vib", info); - if (ret) { - dev_err(info->dev, "VIB IRQ request failed: %d\n", ret); - goto err_irq; - } - - info->supplies[0].supply = "vddvibl"; - info->supplies[1].supply = "vddvibr"; - ret = regulator_bulk_get(info->dev, ARRAY_SIZE(info->supplies), - info->supplies); - if (ret) { - dev_err(info->dev, "couldn't get regulators %d\n", ret); - goto err_regulator; - } - - if (pdata->vddvibl_uV) { - ret = regulator_set_voltage(info->supplies[0].consumer, - pdata->vddvibl_uV, - pdata->vddvibl_uV); - if (ret) { - dev_err(info->dev, "failed to set VDDVIBL volt %d\n", - ret); - goto err_voltage; - } - } - - if (pdata->vddvibr_uV) { - ret = regulator_set_voltage(info->supplies[1].consumer, - pdata->vddvibr_uV, - pdata->vddvibr_uV); - if (ret) { - dev_err(info->dev, "failed to set VDDVIBR volt %d\n", - ret); - goto err_voltage; - } - } - - info->workqueue = alloc_workqueue("twl6040-vibra", 0, 0); - if (info->workqueue == NULL) { - dev_err(info->dev, "couldn't create workqueue\n"); - ret = -ENOMEM; - goto err_voltage; - } - INIT_WORK(&info->play_work, vibra_play_work); - - return 0; - -err_voltage: - regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies); -err_regulator: - free_irq(info->irq, info); -err_irq: - input_unregister_device(info->input_dev); - info->input_dev = NULL; -err_iff: - if (info->input_dev) - input_ff_destroy(info->input_dev); -err_ialloc: - input_free_device(info->input_dev); -err_kzalloc: - kfree(info); - return ret; -} - -static int __devexit twl6040_vibra_remove(struct platform_device *pdev) -{ - struct vibra_info *info = platform_get_drvdata(pdev); - - input_unregister_device(info->input_dev); - free_irq(info->irq, info); - regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies); - destroy_workqueue(info->workqueue); - kfree(info); - - return 0; -} - -static struct platform_driver twl6040_vibra_driver = { - .probe = twl6040_vibra_probe, - .remove = __devexit_p(twl6040_vibra_remove), - .driver = { - .name = "twl6040-vibra", - .owner = THIS_MODULE, - .pm = &twl6040_vibra_pm_ops, - }, -}; - -static int __init twl6040_vibra_init(void) -{ - return platform_driver_register(&twl6040_vibra_driver); -} -module_init(twl6040_vibra_init); - -static void __exit twl6040_vibra_exit(void) -{ - platform_driver_unregister(&twl6040_vibra_driver); -} -module_exit(twl6040_vibra_exit); - -MODULE_ALIAS("platform:twl6040-vibra"); -MODULE_DESCRIPTION("TWL6040 Vibra driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jorge Eduardo Candelaria <jorge.candelaria@ti.com>"); -MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>"); diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 6c21c2986ca..713d43b4e56 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -92,7 +92,7 @@ config LEDS_NET48XX config LEDS_NET5501 tristate "LED Support for Soekris net5501 series Error LED" depends on LEDS_TRIGGERS - depends on X86 && GPIO_CS5535 + depends on X86 && LEDS_GPIO_PLATFORM && GPIO_CS5535 select LEDS_TRIGGER_DEFAULT_ON default n help @@ -182,6 +182,23 @@ config LEDS_GPIO defined as platform devices and/or OpenFirmware platform devices. The code to use these bindings can be selected below. +config LEDS_GPIO_PLATFORM + bool "Platform device bindings for GPIO LEDs" + depends on LEDS_GPIO + default y + help + Let the leds-gpio driver drive LEDs which have been defined as + platform devices. If you don't know what this means, say yes. + +config LEDS_GPIO_OF + bool "OpenFirmware platform device bindings for GPIO LEDs" + depends on LEDS_GPIO && OF_DEVICE + default y + help + Let the leds-gpio driver drive LEDs which have been defined as + of_platform devices. For instance, LEDs which are listed in a "dts" + file. + config LEDS_LP3944 tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip" depends on LEDS_CLASS diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index 3d8bc327a68..b0480c8fbcb 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -165,7 +165,7 @@ static inline int sizeof_gpio_leds_priv(int num_leds) } /* Code to create from OpenFirmware platform devices */ -#ifdef CONFIG_OF_GPIO +#ifdef CONFIG_LEDS_GPIO_OF static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node, *child; @@ -223,13 +223,13 @@ static const struct of_device_id of_gpio_leds_match[] = { { .compatible = "gpio-leds", }, {}, }; -#else /* CONFIG_OF_GPIO */ +#else static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_device *pdev) { return NULL; } #define of_gpio_leds_match NULL -#endif /* CONFIG_OF_GPIO */ +#endif static int __devinit gpio_led_probe(struct platform_device *pdev) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 37b83eb6d70..6ca938a6bf9 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -218,7 +218,7 @@ config TWL4030_POWER and load scripts controlling which resources are switched off/on or reset when a sleep, wakeup or warm reset event occurs. -config MFD_TWL4030_AUDIO +config TWL4030_CODEC bool depends on TWL4030_CORE select MFD_CORE @@ -233,12 +233,6 @@ config TWL6030_PWM Say yes here if you want support for TWL6030 PWM. This is used to control charging LED brightness. -config TWL6040_CORE - bool - depends on TWL4030_CORE && GENERIC_HARDIRQS - select MFD_CORE - default n - config MFD_STMPE bool "Support STMicroelectronics STMPE" depends on I2C=y && GENERIC_HARDIRQS diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 22a280fcb70..d7d47d2a4c7 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -40,9 +40,8 @@ obj-$(CONFIG_MENELAUS) += menelaus.o obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o -obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o +obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o -obj-$(CONFIG_TWL6040_CORE) += twl6040-core.o twl6040-irq.o obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index a2eddc70995..b8f2a4e7f6e 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -110,7 +110,7 @@ #endif #if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE) ||\ - defined(CONFIG_TWL6040_CORE) || defined(CONFIG_TWL6040_CORE_MODULE) + defined(CONFIG_SND_SOC_TWL6040) || defined(CONFIG_SND_SOC_TWL6040_MODULE) #define twl_has_codec() true #else #define twl_has_codec() false @@ -815,19 +815,20 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) return PTR_ERR(child); } - if (twl_has_codec() && pdata->audio && twl_class_is_4030()) { + if (twl_has_codec() && pdata->codec && twl_class_is_4030()) { sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid; child = add_child(sub_chip_id, "twl4030-audio", - pdata->audio, sizeof(*pdata->audio), + pdata->codec, sizeof(*pdata->codec), false, 0, 0); if (IS_ERR(child)) return PTR_ERR(child); } - if (twl_has_codec() && pdata->audio && twl_class_is_6030()) { + /* Phoenix codec driver is probed directly atm */ + if (twl_has_codec() && pdata->codec && twl_class_is_6030()) { sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid; - child = add_child(sub_chip_id, "twl6040", - pdata->audio, sizeof(*pdata->audio), + child = add_child(sub_chip_id, "twl6040-codec", + pdata->codec, sizeof(*pdata->codec), false, 0, 0); if (IS_ERR(child)) return PTR_ERR(child); diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c deleted file mode 100644 index ae51ab5d0e5..00000000000 --- a/drivers/mfd/twl4030-audio.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * MFD driver for twl4030 audio submodule, which contains an audio codec, and - * the vibra control. - * - * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> - * - * Copyright: (C) 2009 Nokia Corporation - * - * 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/module.h> -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/kernel.h> -#include <linux/fs.h> -#include <linux/platform_device.h> -#include <linux/i2c/twl.h> -#include <linux/mfd/core.h> -#include <linux/mfd/twl4030-audio.h> - -#define TWL4030_AUDIO_CELLS 2 - -static struct platform_device *twl4030_audio_dev; - -struct twl4030_audio_resource { - int request_count; - u8 reg; - u8 mask; -}; - -struct twl4030_audio { - unsigned int audio_mclk; - struct mutex mutex; - struct twl4030_audio_resource resource[TWL4030_AUDIO_RES_MAX]; - struct mfd_cell cells[TWL4030_AUDIO_CELLS]; -}; - -/* - * Modify the resource, the function returns the content of the register - * after the modification. - */ -static int twl4030_audio_set_resource(enum twl4030_audio_res id, int enable) -{ - struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev); - u8 val; - - twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, - audio->resource[id].reg); - - if (enable) - val |= audio->resource[id].mask; - else - val &= ~audio->resource[id].mask; - - twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - val, audio->resource[id].reg); - - return val; -} - -static inline int twl4030_audio_get_resource(enum twl4030_audio_res id) -{ - struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev); - u8 val; - - twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, - audio->resource[id].reg); - - return val; -} - -/* - * Enable the resource. - * The function returns with error or the content of the register - */ -int twl4030_audio_enable_resource(enum twl4030_audio_res id) -{ - struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev); - int val; - - if (id >= TWL4030_AUDIO_RES_MAX) { - dev_err(&twl4030_audio_dev->dev, - "Invalid resource ID (%u)\n", id); - return -EINVAL; - } - - mutex_lock(&audio->mutex); - if (!audio->resource[id].request_count) - /* Resource was disabled, enable it */ - val = twl4030_audio_set_resource(id, 1); - else - val = twl4030_audio_get_resource(id); - - audio->resource[id].request_count++; - mutex_unlock(&audio->mutex); - - return val; -} -EXPORT_SYMBOL_GPL(twl4030_audio_enable_resource); - -/* - * Disable the resource. - * The function returns with error or the content of the register - */ -int twl4030_audio_disable_resource(unsigned id) -{ - struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev); - int val; - - if (id >= TWL4030_AUDIO_RES_MAX) { - dev_err(&twl4030_audio_dev->dev, - "Invalid resource ID (%u)\n", id); - return -EINVAL; - } - - mutex_lock(&audio->mutex); - if (!audio->resource[id].request_count) { - dev_err(&twl4030_audio_dev->dev, - "Resource has been disabled already (%u)\n", id); - mutex_unlock(&audio->mutex); - return -EPERM; - } - audio->resource[id].request_count--; - - if (!audio->resource[id].request_count) - /* Resource can be disabled now */ - val = twl4030_audio_set_resource(id, 0); - else - val = twl4030_audio_get_resource(id); - - mutex_unlock(&audio->mutex); - - return val; -} -EXPORT_SYMBOL_GPL(twl4030_audio_disable_resource); - -unsigned int twl4030_audio_get_mclk(void) -{ - struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev); - - return audio->audio_mclk; -} -EXPORT_SYMBOL_GPL(twl4030_audio_get_mclk); - -static int __devinit twl4030_audio_probe(struct platform_device *pdev) -{ - struct twl4030_audio *audio; - struct twl4030_audio_data *pdata = pdev->dev.platform_data; - struct mfd_cell *cell = NULL; - int ret, childs = 0; - u8 val; - - if (!pdata) { - dev_err(&pdev->dev, "Platform data is missing\n"); - return -EINVAL; - } - - /* Configure APLL_INFREQ and disable APLL if enabled */ - val = 0; - switch (pdata->audio_mclk) { - case 19200000: - val |= TWL4030_APLL_INFREQ_19200KHZ; - break; - case 26000000: - val |= TWL4030_APLL_INFREQ_26000KHZ; - break; - case 38400000: - val |= TWL4030_APLL_INFREQ_38400KHZ; - break; - default: - dev_err(&pdev->dev, "Invalid audio_mclk\n"); - return -EINVAL; - } - twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - val, TWL4030_REG_APLL_CTL); - - audio = kzalloc(sizeof(struct twl4030_audio), GFP_KERNEL); - if (!audio) - return -ENOMEM; - - platform_set_drvdata(pdev, audio); - - twl4030_audio_dev = pdev; - mutex_init(&audio->mutex); - audio->audio_mclk = pdata->audio_mclk; - - /* Codec power */ - audio->resource[TWL4030_AUDIO_RES_POWER].reg = TWL4030_REG_CODEC_MODE; - audio->resource[TWL4030_AUDIO_RES_POWER].mask = TWL4030_CODECPDZ; - - /* PLL */ - audio->resource[TWL4030_AUDIO_RES_APLL].reg = TWL4030_REG_APLL_CTL; - audio->resource[TWL4030_AUDIO_RES_APLL].mask = TWL4030_APLL_EN; - - if (pdata->codec) { - cell = &audio->cells[childs]; - cell->name = "twl4030-codec"; - cell->platform_data = pdata->codec; - cell->pdata_size = sizeof(*pdata->codec); - childs++; - } - if (pdata->vibra) { - cell = &audio->cells[childs]; - cell->name = "twl4030-vibra"; - cell->platform_data = pdata->vibra; - cell->pdata_size = sizeof(*pdata->vibra); - childs++; - } - - if (childs) - ret = mfd_add_devices(&pdev->dev, pdev->id, audio->cells, - childs, NULL, 0); - else { - dev_err(&pdev->dev, "No platform data found for childs\n"); - ret = -ENODEV; - } - - if (!ret) - return 0; - - platform_set_drvdata(pdev, NULL); - kfree(audio); - twl4030_audio_dev = NULL; - return ret; -} - -static int __devexit twl4030_audio_remove(struct platform_device *pdev) -{ - struct twl4030_audio *audio = platform_get_drvdata(pdev); - - mfd_remove_devices(&pdev->dev); - platform_set_drvdata(pdev, NULL); - kfree(audio); - twl4030_audio_dev = NULL; - - return 0; -} - -MODULE_ALIAS("platform:twl4030-audio"); - -static struct platform_driver twl4030_audio_driver = { - .probe = twl4030_audio_probe, - .remove = __devexit_p(twl4030_audio_remove), - .driver = { - .owner = THIS_MODULE, - .name = "twl4030-audio", - }, -}; - -static int __devinit twl4030_audio_init(void) -{ - return platform_driver_register(&twl4030_audio_driver); -} -module_init(twl4030_audio_init); - -static void __devexit twl4030_audio_exit(void) -{ - platform_driver_unregister(&twl4030_audio_driver); -} -module_exit(twl4030_audio_exit); - -MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/twl4030-codec.c b/drivers/mfd/twl4030-codec.c new file mode 100644 index 00000000000..2bf4136464c --- /dev/null +++ b/drivers/mfd/twl4030-codec.c @@ -0,0 +1,277 @@ +/* + * MFD driver for twl4030 codec submodule + * + * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> + * + * Copyright: (C) 2009 Nokia Corporation + * + * 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/module.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/platform_device.h> +#include <linux/i2c/twl.h> +#include <linux/mfd/core.h> +#include <linux/mfd/twl4030-codec.h> + +#define TWL4030_CODEC_CELLS 2 + +static struct platform_device *twl4030_codec_dev; + +struct twl4030_codec_resource { + int request_count; + u8 reg; + u8 mask; +}; + +struct twl4030_codec { + unsigned int audio_mclk; + struct mutex mutex; + struct twl4030_codec_resource resource[TWL4030_CODEC_RES_MAX]; + struct mfd_cell cells[TWL4030_CODEC_CELLS]; +}; + +/* + * Modify the resource, the function returns the content of the register + * after the modification. + */ +static int twl4030_codec_set_resource(enum twl4030_codec_res id, int enable) +{ + struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev); + u8 val; + + twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, + codec->resource[id].reg); + + if (enable) + val |= codec->resource[id].mask; + else + val &= ~codec->resource[id].mask; + + twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, + val, codec->resource[id].reg); + + return val; +} + +static inline int twl4030_codec_get_resource(enum twl4030_codec_res id) +{ + struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev); + u8 val; + + twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, + codec->resource[id].reg); + + return val; +} + +/* + * Enable the resource. + * The function returns with error or the content of the register + */ +int twl4030_codec_enable_resource(enum twl4030_codec_res id) +{ + struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev); + int val; + + if (id >= TWL4030_CODEC_RES_MAX) { + dev_err(&twl4030_codec_dev->dev, + "Invalid resource ID (%u)\n", id); + return -EINVAL; + } + + mutex_lock(&codec->mutex); + if (!codec->resource[id].request_count) + /* Resource was disabled, enable it */ + val = twl4030_codec_set_resource(id, 1); + else + val = twl4030_codec_get_resource(id); + + codec->resource[id].request_count++; + mutex_unlock(&codec->mutex); + + return val; +} +EXPORT_SYMBOL_GPL(twl4030_codec_enable_resource); + +/* + * Disable the resource. + * The function returns with error or the content of the register + */ +int twl4030_codec_disable_resource(unsigned id) +{ + struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev); + int val; + + if (id >= TWL4030_CODEC_RES_MAX) { + dev_err(&twl4030_codec_dev->dev, + "Invalid resource ID (%u)\n", id); + return -EINVAL; + } + + mutex_lock(&codec->mutex); + if (!codec->resource[id].request_count) { + dev_err(&twl4030_codec_dev->dev, + "Resource has been disabled already (%u)\n", id); + mutex_unlock(&codec->mutex); + return -EPERM; + } + codec->resource[id].request_count--; + + if (!codec->resource[id].request_count) + /* Resource can be disabled now */ + val = twl4030_codec_set_resource(id, 0); + else + val = twl4030_codec_get_resource(id); + + mutex_unlock(&codec->mutex); + + return val; +} +EXPORT_SYMBOL_GPL(twl4030_codec_disable_resource); + +unsigned int twl4030_codec_get_mclk(void) +{ + struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev); + + return codec->audio_mclk; +} +EXPORT_SYMBOL_GPL(twl4030_codec_get_mclk); + +static int __devinit twl4030_codec_probe(struct platform_device *pdev) +{ + struct twl4030_codec *codec; + struct twl4030_codec_data *pdata = pdev->dev.platform_data; + struct mfd_cell *cell = NULL; + int ret, childs = 0; + u8 val; + + if (!pdata) { + dev_err(&pdev->dev, "Platform data is missing\n"); + return -EINVAL; + } + + /* Configure APLL_INFREQ and disable APLL if enabled */ + val = 0; + switch (pdata->audio_mclk) { + case 19200000: + val |= TWL4030_APLL_INFREQ_19200KHZ; + break; + case 26000000: + val |= TWL4030_APLL_INFREQ_26000KHZ; + break; + case 38400000: + val |= TWL4030_APLL_INFREQ_38400KHZ; + break; + default: + dev_err(&pdev->dev, "Invalid audio_mclk\n"); + return -EINVAL; + } + twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, + val, TWL4030_REG_APLL_CTL); + + codec = kzalloc(sizeof(struct twl4030_codec), GFP_KERNEL); + if (!codec) + return -ENOMEM; + + platform_set_drvdata(pdev, codec); + + twl4030_codec_dev = pdev; + mutex_init(&codec->mutex); + codec->audio_mclk = pdata->audio_mclk; + + /* Codec power */ + codec->resource[TWL4030_CODEC_RES_POWER].reg = TWL4030_REG_CODEC_MODE; + codec->resource[TWL4030_CODEC_RES_POWER].mask = TWL4030_CODECPDZ; + + /* PLL */ + codec->resource[TWL4030_CODEC_RES_APLL].reg = TWL4030_REG_APLL_CTL; + codec->resource[TWL4030_CODEC_RES_APLL].mask = TWL4030_APLL_EN; + + if (pdata->audio) { + cell = &codec->cells[childs]; + cell->name = "twl4030-codec"; + cell->platform_data = pdata->audio; + cell->pdata_size = sizeof(*pdata->audio); + childs++; + } + if (pdata->vibra) { + cell = &codec->cells[childs]; + cell->name = "twl4030-vibra"; + cell->platform_data = pdata->vibra; + cell->pdata_size = sizeof(*pdata->vibra); + childs++; + } + + if (childs) + ret = mfd_add_devices(&pdev->dev, pdev->id, codec->cells, + childs, NULL, 0); + else { + dev_err(&pdev->dev, "No platform data found for childs\n"); + ret = -ENODEV; + } + + if (!ret) + return 0; + + platform_set_drvdata(pdev, NULL); + kfree(codec); + twl4030_codec_dev = NULL; + return ret; +} + +static int __devexit twl4030_codec_remove(struct platform_device *pdev) +{ + struct twl4030_codec *codec = platform_get_drvdata(pdev); + + mfd_remove_devices(&pdev->dev); + platform_set_drvdata(pdev, NULL); + kfree(codec); + twl4030_codec_dev = NULL; + + return 0; +} + +MODULE_ALIAS("platform:twl4030-audio"); + +static struct platform_driver twl4030_codec_driver = { + .probe = twl4030_codec_probe, + .remove = __devexit_p(twl4030_codec_remove), + .driver = { + .owner = THIS_MODULE, + .name = "twl4030-audio", + }, +}; + +static int __devinit twl4030_codec_init(void) +{ + return platform_driver_register(&twl4030_codec_driver); +} +module_init(twl4030_codec_init); + +static void __devexit twl4030_codec_exit(void) +{ + platform_driver_unregister(&twl4030_codec_driver); +} +module_exit(twl4030_codec_exit); + +MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c deleted file mode 100644 index 24d436c2fe4..00000000000 --- a/drivers/mfd/twl6040-core.c +++ /dev/null @@ -1,620 +0,0 @@ -/* - * MFD driver for TWL6040 audio device - * - * Authors: Misael Lopez Cruz <misael.lopez@ti.com> - * Jorge Eduardo Candelaria <jorge.candelaria@ti.com> - * Peter Ujfalusi <peter.ujfalusi@ti.com> - * - * Copyright: (C) 2011 Texas Instruments, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License 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/module.h> -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/gpio.h> -#include <linux/delay.h> -#include <linux/i2c/twl.h> -#include <linux/mfd/core.h> -#include <linux/mfd/twl6040.h> - -static struct platform_device *twl6040_dev; - -int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg) -{ - int ret; - u8 val = 0; - - mutex_lock(&twl6040->io_mutex); - ret = twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &val, reg); - if (ret < 0) { - mutex_unlock(&twl6040->io_mutex); - return ret; - } - mutex_unlock(&twl6040->io_mutex); - - return val; -} -EXPORT_SYMBOL(twl6040_reg_read); - -int twl6040_reg_write(struct twl6040 *twl6040, unsigned int reg, u8 val) -{ - int ret; - - mutex_lock(&twl6040->io_mutex); - ret = twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, val, reg); - mutex_unlock(&twl6040->io_mutex); - - return ret; -} -EXPORT_SYMBOL(twl6040_reg_write); - -int twl6040_set_bits(struct twl6040 *twl6040, unsigned int reg, u8 mask) -{ - int ret; - u8 val; - - mutex_lock(&twl6040->io_mutex); - ret = twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &val, reg); - if (ret) - goto out; - - val |= mask; - ret = twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, val, reg); -out: - mutex_unlock(&twl6040->io_mutex); - return ret; -} -EXPORT_SYMBOL(twl6040_set_bits); - -int twl6040_clear_bits(struct twl6040 *twl6040, unsigned int reg, u8 mask) -{ - int ret; - u8 val; - - mutex_lock(&twl6040->io_mutex); - ret = twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &val, reg); - if (ret) - goto out; - - val &= ~mask; - ret = twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, val, reg); -out: - mutex_unlock(&twl6040->io_mutex); - return ret; -} -EXPORT_SYMBOL(twl6040_clear_bits); - -/* twl6040 codec manual power-up sequence */ -static int twl6040_power_up(struct twl6040 *twl6040) -{ - u8 ldoctl, ncpctl, lppllctl; - int ret; - - /* enable high-side LDO, reference system and internal oscillator */ - ldoctl = TWL6040_HSLDOENA | TWL6040_REFENA | TWL6040_OSCENA; - ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl); - if (ret) - return ret; - usleep_range(10000, 10500); - - /* enable negative charge pump */ - ncpctl = TWL6040_NCPENA; - ret = twl6040_reg_write(twl6040, TWL6040_REG_NCPCTL, ncpctl); - if (ret) - goto ncp_err; - usleep_range(1000, 1500); - - /* enable low-side LDO */ - ldoctl |= TWL6040_LSLDOENA; - ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl); - if (ret) - goto lsldo_err; - usleep_range(1000, 1500); - - /* enable low-power PLL */ - lppllctl = TWL6040_LPLLENA; - ret = twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); - if (ret) - goto lppll_err; - usleep_range(5000, 5500); - - /* disable internal oscillator */ - ldoctl &= ~TWL6040_OSCENA; - ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl); - if (ret) - goto osc_err; - - return 0; - -osc_err: - lppllctl &= ~TWL6040_LPLLENA; - twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); -lppll_err: - ldoctl &= ~TWL6040_LSLDOENA; - twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl); -lsldo_err: - ncpctl &= ~TWL6040_NCPENA; - twl6040_reg_write(twl6040, TWL6040_REG_NCPCTL, ncpctl); -ncp_err: - ldoctl &= ~(TWL6040_HSLDOENA | TWL6040_REFENA | TWL6040_OSCENA); - twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl); - - return ret; -} - -/* twl6040 manual power-down sequence */ -static void twl6040_power_down(struct twl6040 *twl6040) -{ - u8 ncpctl, ldoctl, lppllctl; - - ncpctl = twl6040_reg_read(twl6040, TWL6040_REG_NCPCTL); - ldoctl = twl6040_reg_read(twl6040, TWL6040_REG_LDOCTL); - lppllctl = twl6040_reg_read(twl6040, TWL6040_REG_LPPLLCTL); - - /* enable internal oscillator */ - ldoctl |= TWL6040_OSCENA; - twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl); - usleep_range(1000, 1500); - - /* disable low-power PLL */ - lppllctl &= ~TWL6040_LPLLENA; - twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); - - /* disable low-side LDO */ - ldoctl &= ~TWL6040_LSLDOENA; - twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl); - - /* disable negative charge pump */ - ncpctl &= ~TWL6040_NCPENA; - twl6040_reg_write(twl6040, TWL6040_REG_NCPCTL, ncpctl); - - /* disable high-side LDO, reference system and internal oscillator */ - ldoctl &= ~(TWL6040_HSLDOENA | TWL6040_REFENA | TWL6040_OSCENA); - twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl); -} - -static irqreturn_t twl6040_naudint_handler(int irq, void *data) -{ - struct twl6040 *twl6040 = data; - u8 intid, status; - - intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID); - - if (intid & TWL6040_READYINT) - complete(&twl6040->ready); - - if (intid & TWL6040_THINT) { - status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS); - if (status & TWL6040_TSHUTDET) { - dev_warn(&twl6040_dev->dev, - "Thermal shutdown, powering-off"); - twl6040_power(twl6040, 0); - } else { - dev_warn(&twl6040_dev->dev, - "Leaving thermal shutdown, powering-on"); - twl6040_power(twl6040, 1); - } - } - - return IRQ_HANDLED; -} - -static int twl6040_power_up_completion(struct twl6040 *twl6040, - int naudint) -{ - int time_left; - u8 intid; - - time_left = wait_for_completion_timeout(&twl6040->ready, - msecs_to_jiffies(144)); - if (!time_left) { - intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID); - if (!(intid & TWL6040_READYINT)) { - dev_err(&twl6040_dev->dev, - "timeout waiting for READYINT\n"); - return -ETIMEDOUT; - } - } - - return 0; -} - -int twl6040_power(struct twl6040 *twl6040, int on) -{ - int audpwron = twl6040->audpwron; - int naudint = twl6040->irq; - int ret = 0; - - mutex_lock(&twl6040->mutex); - - if (on) { - /* already powered-up */ - if (twl6040->power_count++) - goto out; - - if (gpio_is_valid(audpwron)) { - /* use AUDPWRON line */ - gpio_set_value(audpwron, 1); - /* wait for power-up completion */ - ret = twl6040_power_up_completion(twl6040, naudint); - if (ret) { - dev_err(&twl6040_dev->dev, - "automatic power-down failed\n"); - twl6040->power_count = 0; - goto out; - } - } else { - /* use manual power-up sequence */ - ret = twl6040_power_up(twl6040); - if (ret) { - dev_err(&twl6040_dev->dev, - "manual power-up failed\n"); - twl6040->power_count = 0; - goto out; - } - } - /* Default PLL configuration after power up */ - twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL; - twl6040->sysclk = 19200000; - } else { - /* already powered-down */ - if (!twl6040->power_count) { - dev_err(&twl6040_dev->dev, - "device is already powered-off\n"); - ret = -EPERM; - goto out; - } - - if (--twl6040->power_count) - goto out; - - if (gpio_is_valid(audpwron)) { - /* use AUDPWRON line */ - gpio_set_value(audpwron, 0); - - /* power-down sequence latency */ - usleep_range(500, 700); - } else { - /* use manual power-down sequence */ - twl6040_power_down(twl6040); - } - twl6040->sysclk = 0; - } - -out: - mutex_unlock(&twl6040->mutex); - return ret; -} -EXPORT_SYMBOL(twl6040_power); - -int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, - unsigned int freq_in, unsigned int freq_out) -{ - u8 hppllctl, lppllctl; - int ret = 0; - - mutex_lock(&twl6040->mutex); - - hppllctl = twl6040_reg_read(twl6040, TWL6040_REG_HPPLLCTL); - lppllctl = twl6040_reg_read(twl6040, TWL6040_REG_LPPLLCTL); - - switch (pll_id) { - case TWL6040_SYSCLK_SEL_LPPLL: - /* low-power PLL divider */ - switch (freq_out) { - case 17640000: - lppllctl |= TWL6040_LPLLFIN; - break; - case 19200000: - lppllctl &= ~TWL6040_LPLLFIN; - break; - default: - dev_err(&twl6040_dev->dev, - "freq_out %d not supported\n", freq_out); - ret = -EINVAL; - goto pll_out; - } - twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); - - switch (freq_in) { - case 32768: - lppllctl |= TWL6040_LPLLENA; - twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, - lppllctl); - mdelay(5); - lppllctl &= ~TWL6040_HPLLSEL; - twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, - lppllctl); - hppllctl &= ~TWL6040_HPLLENA; - twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL, - hppllctl); - break; - default: - dev_err(&twl6040_dev->dev, - "freq_in %d not supported\n", freq_in); - ret = -EINVAL; - goto pll_out; - } - break; - case TWL6040_SYSCLK_SEL_HPPLL: - /* high-performance PLL can provide only 19.2 MHz */ - if (freq_out != 19200000) { - dev_err(&twl6040_dev->dev, - "freq_out %d not supported\n", freq_out); - ret = -EINVAL; - goto pll_out; - } - - hppllctl &= ~TWL6040_MCLK_MSK; - - switch (freq_in) { - case 12000000: - /* PLL enabled, active mode */ - hppllctl |= TWL6040_MCLK_12000KHZ | - TWL6040_HPLLENA; - break; - case 19200000: - /* - * PLL disabled - * (enable PLL if MCLK jitter quality - * doesn't meet specification) - */ - hppllctl |= TWL6040_MCLK_19200KHZ; - break; - case 26000000: - /* PLL enabled, active mode */ - hppllctl |= TWL6040_MCLK_26000KHZ | - TWL6040_HPLLENA; - break; - case 38400000: - /* PLL enabled, active mode */ - hppllctl |= TWL6040_MCLK_38400KHZ | - TWL6040_HPLLENA; - break; - default: - dev_err(&twl6040_dev->dev, - "freq_in %d not supported\n", freq_in); - ret = -EINVAL; - goto pll_out; - } - - /* enable clock slicer to ensure input waveform is square */ - hppllctl |= TWL6040_HPLLSQRENA; - - twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL, hppllctl); - usleep_range(500, 700); - lppllctl |= TWL6040_HPLLSEL; - twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); - lppllctl &= ~TWL6040_LPLLENA; - twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); - break; - default: - dev_err(&twl6040_dev->dev, "unknown pll id %d\n", pll_id); - ret = -EINVAL; - goto pll_out; - } - - twl6040->sysclk = freq_out; - twl6040->pll = pll_id; - -pll_out: - mutex_unlock(&twl6040->mutex); - return ret; -} -EXPORT_SYMBOL(twl6040_set_pll); - -int twl6040_get_pll(struct twl6040 *twl6040) -{ - if (twl6040->power_count) - return twl6040->pll; - else - return -ENODEV; -} -EXPORT_SYMBOL(twl6040_get_pll); - -unsigned int twl6040_get_sysclk(struct twl6040 *twl6040) -{ - return twl6040->sysclk; -} -EXPORT_SYMBOL(twl6040_get_sysclk); - -static struct resource twl6040_vibra_rsrc[] = { - { - .flags = IORESOURCE_IRQ, - }, -}; - -static struct resource twl6040_codec_rsrc[] = { - { - .flags = IORESOURCE_IRQ, - }, -}; - -static int __devinit twl6040_probe(struct platform_device *pdev) -{ - struct twl4030_audio_data *pdata = pdev->dev.platform_data; - struct twl6040 *twl6040; - struct mfd_cell *cell = NULL; - int ret, children = 0; - - if (!pdata) { - dev_err(&pdev->dev, "Platform data is missing\n"); - return -EINVAL; - } - - /* In order to operate correctly we need valid interrupt config */ - if (!pdata->naudint_irq || !pdata->irq_base) { - dev_err(&pdev->dev, "Invalid IRQ configuration\n"); - return -EINVAL; - } - - twl6040 = kzalloc(sizeof(struct twl6040), GFP_KERNEL); - if (!twl6040) - return -ENOMEM; - - platform_set_drvdata(pdev, twl6040); - - twl6040_dev = pdev; - twl6040->dev = &pdev->dev; - twl6040->audpwron = pdata->audpwron_gpio; - twl6040->irq = pdata->naudint_irq; - twl6040->irq_base = pdata->irq_base; - - mutex_init(&twl6040->mutex); - mutex_init(&twl6040->io_mutex); - init_completion(&twl6040->ready); - - twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV); - - if (gpio_is_valid(twl6040->audpwron)) { - ret = gpio_request(twl6040->audpwron, "audpwron"); - if (ret) - goto gpio1_err; - - ret = gpio_direction_output(twl6040->audpwron, 0); - if (ret) - goto gpio2_err; - } - - /* ERRATA: Automatic power-up is not possible in ES1.0 */ - if (twl6040->rev == TWL6040_REV_ES1_0) - twl6040->audpwron = -EINVAL; - - /* codec interrupt */ - ret = twl6040_irq_init(twl6040); - if (ret) - goto gpio2_err; - - ret = request_threaded_irq(twl6040->irq_base + TWL6040_IRQ_READY, - NULL, twl6040_naudint_handler, 0, - "twl6040_irq_ready", twl6040); - if (ret) { - dev_err(twl6040->dev, "READY IRQ request failed: %d\n", - ret); - goto irq_err; - } - - /* dual-access registers controlled by I2C only */ - twl6040_set_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_I2CSEL); - - if (pdata->codec) { - int irq = twl6040->irq_base + TWL6040_IRQ_PLUG; - - cell = &twl6040->cells[children]; - cell->name = "twl6040-codec"; - twl6040_codec_rsrc[0].start = irq; - twl6040_codec_rsrc[0].end = irq; - cell->resources = twl6040_codec_rsrc; - cell->num_resources = ARRAY_SIZE(twl6040_codec_rsrc); - cell->platform_data = pdata->codec; - cell->pdata_size = sizeof(*pdata->codec); - children++; - } - - if (pdata->vibra) { - int irq = twl6040->irq_base + TWL6040_IRQ_VIB; - - cell = &twl6040->cells[children]; - cell->name = "twl6040-vibra"; - twl6040_vibra_rsrc[0].start = irq; - twl6040_vibra_rsrc[0].end = irq; - cell->resources = twl6040_vibra_rsrc; - cell->num_resources = ARRAY_SIZE(twl6040_vibra_rsrc); - - cell->platform_data = pdata->vibra; - cell->pdata_size = sizeof(*pdata->vibra); - children++; - } - - if (children) { - ret = mfd_add_devices(&pdev->dev, pdev->id, twl6040->cells, - children, NULL, 0); - if (ret) - goto mfd_err; - } else { - dev_err(&pdev->dev, "No platform data found for children\n"); - ret = -ENODEV; - goto mfd_err; - } - - return 0; - -mfd_err: - free_irq(twl6040->irq_base + TWL6040_IRQ_READY, twl6040); -irq_err: - twl6040_irq_exit(twl6040); -gpio2_err: - if (gpio_is_valid(twl6040->audpwron)) - gpio_free(twl6040->audpwron); -gpio1_err: - platform_set_drvdata(pdev, NULL); - kfree(twl6040); - twl6040_dev = NULL; - return ret; -} - -static int __devexit twl6040_remove(struct platform_device *pdev) -{ - struct twl6040 *twl6040 = platform_get_drvdata(pdev); - - if (twl6040->power_count) - twl6040_power(twl6040, 0); - - if (gpio_is_valid(twl6040->audpwron)) - gpio_free(twl6040->audpwron); - - free_irq(twl6040->irq_base + TWL6040_IRQ_READY, twl6040); - twl6040_irq_exit(twl6040); - - mfd_remove_devices(&pdev->dev); - platform_set_drvdata(pdev, NULL); - kfree(twl6040); - twl6040_dev = NULL; - - return 0; -} - -static struct platform_driver twl6040_driver = { - .probe = twl6040_probe, - .remove = __devexit_p(twl6040_remove), - .driver = { - .owner = THIS_MODULE, - .name = "twl6040", - }, -}; - -static int __devinit twl6040_init(void) -{ - return platform_driver_register(&twl6040_driver); -} -module_init(twl6040_init); - -static void __devexit twl6040_exit(void) -{ - platform_driver_unregister(&twl6040_driver); -} - -module_exit(twl6040_exit); - -MODULE_DESCRIPTION("TWL6040 MFD"); -MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>"); -MODULE_AUTHOR("Jorge Eduardo Candelaria <jorge.candelaria@ti.com>"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:twl6040"); diff --git a/drivers/mfd/twl6040-irq.c b/drivers/mfd/twl6040-irq.c deleted file mode 100644 index b3f8ddaa28a..00000000000 --- a/drivers/mfd/twl6040-irq.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Interrupt controller support for TWL6040 - * - * Author: Misael Lopez Cruz <misael.lopez@ti.com> - * - * Copyright: (C) 2011 Texas Instruments, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License 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/kernel.h> -#include <linux/module.h> -#include <linux/irq.h> -#include <linux/interrupt.h> -#include <linux/mfd/core.h> -#include <linux/mfd/twl6040.h> - -struct twl6040_irq_data { - int mask; - int status; -}; - -static struct twl6040_irq_data twl6040_irqs[] = { - { - .mask = TWL6040_THMSK, - .status = TWL6040_THINT, - }, - { - .mask = TWL6040_PLUGMSK, - .status = TWL6040_PLUGINT | TWL6040_UNPLUGINT, - }, - { - .mask = TWL6040_HOOKMSK, - .status = TWL6040_HOOKINT, - }, - { - .mask = TWL6040_HFMSK, - .status = TWL6040_HFINT, - }, - { - .mask = TWL6040_VIBMSK, - .status = TWL6040_VIBINT, - }, - { - .mask = TWL6040_READYMSK, - .status = TWL6040_READYINT, - }, -}; - -static inline -struct twl6040_irq_data *irq_to_twl6040_irq(struct twl6040 *twl6040, - int irq) -{ - return &twl6040_irqs[irq - twl6040->irq_base]; -} - -static void twl6040_irq_lock(struct irq_data *data) -{ - struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data); - - mutex_lock(&twl6040->irq_mutex); -} - -static void twl6040_irq_sync_unlock(struct irq_data *data) -{ - struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data); - - /* write back to hardware any change in irq mask */ - if (twl6040->irq_masks_cur != twl6040->irq_masks_cache) { - twl6040->irq_masks_cache = twl6040->irq_masks_cur; - twl6040_reg_write(twl6040, TWL6040_REG_INTMR, - twl6040->irq_masks_cur); - } - - mutex_unlock(&twl6040->irq_mutex); -} - -static void twl6040_irq_enable(struct irq_data *data) -{ - struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data); - struct twl6040_irq_data *irq_data = irq_to_twl6040_irq(twl6040, - data->irq); - - twl6040->irq_masks_cur &= ~irq_data->mask; -} - -static void twl6040_irq_disable(struct irq_data *data) -{ - struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data); - struct twl6040_irq_data *irq_data = irq_to_twl6040_irq(twl6040, - data->irq); - - twl6040->irq_masks_cur |= irq_data->mask; -} - -static struct irq_chip twl6040_irq_chip = { - .name = "twl6040", - .irq_bus_lock = twl6040_irq_lock, - .irq_bus_sync_unlock = twl6040_irq_sync_unlock, - .irq_enable = twl6040_irq_enable, - .irq_disable = twl6040_irq_disable, -}; - -static irqreturn_t twl6040_irq_thread(int irq, void *data) -{ - struct twl6040 *twl6040 = data; - u8 intid; - int i; - - intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID); - - /* apply masking and report (backwards to handle READYINT first) */ - for (i = ARRAY_SIZE(twl6040_irqs) - 1; i >= 0; i--) { - if (twl6040->irq_masks_cur & twl6040_irqs[i].mask) - intid &= ~twl6040_irqs[i].status; - if (intid & twl6040_irqs[i].status) - handle_nested_irq(twl6040->irq_base + i); - } - - /* ack unmasked irqs */ - twl6040_reg_write(twl6040, TWL6040_REG_INTID, intid); - - return IRQ_HANDLED; -} - -int twl6040_irq_init(struct twl6040 *twl6040) -{ - int cur_irq, ret; - u8 val; - - mutex_init(&twl6040->irq_mutex); - - /* mask the individual interrupt sources */ - twl6040->irq_masks_cur = TWL6040_ALLINT_MSK; - twl6040->irq_masks_cache = TWL6040_ALLINT_MSK; - twl6040_reg_write(twl6040, TWL6040_REG_INTMR, TWL6040_ALLINT_MSK); - - /* Register them with genirq */ - for (cur_irq = twl6040->irq_base; - cur_irq < twl6040->irq_base + ARRAY_SIZE(twl6040_irqs); - cur_irq++) { - irq_set_chip_data(cur_irq, twl6040); - irq_set_chip_and_handler(cur_irq, &twl6040_irq_chip, - handle_level_irq); - irq_set_nested_thread(cur_irq, 1); - - /* ARM needs us to explicitly flag the IRQ as valid - * and will set them noprobe when we do so. */ -#ifdef CONFIG_ARM - set_irq_flags(cur_irq, IRQF_VALID); -#else - irq_set_noprobe(cur_irq); -#endif - } - - ret = request_threaded_irq(twl6040->irq, NULL, twl6040_irq_thread, - IRQF_ONESHOT, "twl6040", twl6040); - if (ret) { - dev_err(twl6040->dev, "failed to request IRQ %d: %d\n", - twl6040->irq, ret); - return ret; - } - - /* reset interrupts */ - val = twl6040_reg_read(twl6040, TWL6040_REG_INTID); - - /* interrupts cleared on write */ - twl6040_clear_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_INTCLRMODE); - - return 0; -} -EXPORT_SYMBOL(twl6040_irq_init); - -void twl6040_irq_exit(struct twl6040 *twl6040) -{ - free_irq(twl6040->irq, twl6040); -} -EXPORT_SYMBOL(twl6040_irq_exit); diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 14aa213b00d..cc20e025932 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -715,13 +715,13 @@ static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) int burstlen, ret; /* - * use burstlen of 64 (16 words) in 4 bit mode (--> reg value 0) - * use burstlen of 16 (4 words) in 1 bit mode (--> reg value 16) + * use burstlen of 64 in 4 bit mode (--> reg value 0) + * use burstlen of 16 in 1 bit mode (--> reg value 16) */ if (ios->bus_width == MMC_BUS_WIDTH_4) - burstlen = 16; + burstlen = 64; else - burstlen = 4; + burstlen = 16; if (mxcmci_use_dma(host) && burstlen != host->burstlen) { host->burstlen = burstlen; diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index 3007662ac61..905960338fb 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c @@ -21,9 +21,8 @@ #include <linux/slab.h> /** - * of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API + * of_get_gpio_flags - Get a GPIO number and flags to use with GPIO API * @np: device node to get GPIO from - * @propname: property name containing gpio specifier(s) * @index: index of the GPIO * @flags: a flags pointer to fill in * @@ -31,8 +30,8 @@ * value on the error condition. If @flags is not NULL the function also fills * in flags for the GPIO. */ -int of_get_named_gpio_flags(struct device_node *np, const char *propname, - int index, enum of_gpio_flags *flags) +int of_get_gpio_flags(struct device_node *np, int index, + enum of_gpio_flags *flags) { int ret; struct device_node *gpio_np; @@ -41,7 +40,7 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname, const void *gpio_spec; const __be32 *gpio_cells; - ret = of_parse_phandles_with_args(np, propname, "#gpio-cells", index, + ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index, &gpio_np, &gpio_spec); if (ret) { pr_debug("%s: can't parse gpios property\n", __func__); @@ -80,7 +79,7 @@ err0: pr_debug("%s exited with status %d\n", __func__, ret); return ret; } -EXPORT_SYMBOL(of_get_named_gpio_flags); +EXPORT_SYMBOL(of_get_gpio_flags); /** * of_gpio_count - Count GPIOs for a device diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index 69ae2fd2240..81af2b3bcc0 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -48,6 +48,9 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { int ret; + if (platform_scoop_config->pcmcia_init) + platform_scoop_config->pcmcia_init(); + /* Register interrupts */ if (SCOOP_DEV[skt->nr].cd_irq >= 0) { struct pcmcia_irqs cd_irq; diff --git a/drivers/pcmcia/pxa2xx_trizeps4.c b/drivers/pcmcia/pxa2xx_trizeps4.c index 57ddb969d88..b829e655457 100644 --- a/drivers/pcmcia/pxa2xx_trizeps4.c +++ b/drivers/pcmcia/pxa2xx_trizeps4.c @@ -55,6 +55,10 @@ static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt) } skt->socket.pci_irq = IRQ_GPIO(GPIO_PRDY); break; + +#ifndef CONFIG_MACH_TRIZEPS_CONXS + case 1: +#endif default: break; } diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 8f41e112346..636144cea93 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -457,6 +457,7 @@ config SERIAL_SAMSUNG_UARTS_4 config SERIAL_SAMSUNG_UARTS int depends on ARM && PLAT_SAMSUNG + default 2 if ARCH_S3C2400 default 6 if ARCH_S5P6450 default 4 if SERIAL_SAMSUNG_UARTS_4 default 3 @@ -488,6 +489,13 @@ config SERIAL_SAMSUNG_CONSOLE your boot loader about how to pass options to the kernel at boot time.) +config SERIAL_S3C2400 + tristate "Samsung S3C2410 Serial port support" + depends on ARM && SERIAL_SAMSUNG && CPU_S3C2400 + default y if CPU_S3C2400 + help + Serial port support for the Samsung S3C2400 SoC + config SERIAL_S3C2410 tristate "Samsung S3C2410 Serial port support" depends on SERIAL_SAMSUNG && CPU_S3C2410 @@ -511,6 +519,13 @@ config SERIAL_S3C2440 help Serial port support for the Samsung S3C2440, S3C2416 and S3C2442 SoC +config SERIAL_S3C24A0 + tristate "Samsung S3C24A0 Serial port support" + depends on SERIAL_SAMSUNG && CPU_S3C24A0 + default y if CPU_S3C24A0 + help + Serial port support for the Samsung S3C24A0 SoC + config SERIAL_S3C6400 tristate "Samsung S3C6400/S3C6410/S5P6440/S5P6450/S5PC100 Serial port support" depends on SERIAL_SAMSUNG && (CPU_S3C6400 || CPU_S3C6410 || CPU_S5P6440 || CPU_S5P6450 || CPU_S5PC100) diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 83b4da6a106..cb2628fee4c 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -38,9 +38,11 @@ obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o +obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o +obj-$(CONFIG_SERIAL_S3C24A0) += s3c24a0.o obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o obj-$(CONFIG_SERIAL_S5PV210) += s5pv210.o obj-$(CONFIG_SERIAL_MAX3100) += max3100.o diff --git a/drivers/tty/serial/s3c2400.c b/drivers/tty/serial/s3c2400.c new file mode 100644 index 00000000000..d13051b3df8 --- /dev/null +++ b/drivers/tty/serial/s3c2400.c @@ -0,0 +1,105 @@ +/* + * Driver for Samsung SoC onboard UARTs. + * + * Ben Dooks, Copyright (c) 2003-2005 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * + * 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/module.h> +#include <linux/ioport.h> +#include <linux/io.h> +#include <linux/platform_device.h> + +#include <asm/irq.h> + +#include <mach/hardware.h> + +#include <plat/regs-serial.h> +#include <mach/regs-gpio.h> + +#include "samsung.h" + +static int s3c2400_serial_getsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + clk->divisor = 1; + clk->name = "pclk"; + + return 0; +} + +static int s3c2400_serial_setsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + return 0; +} + +static int s3c2400_serial_resetport(struct uart_port *port, + struct s3c2410_uartcfg *cfg) +{ + dbg("s3c2400_serial_resetport: port=%p (%08lx), cfg=%p\n", + port, port->mapbase, cfg); + + wr_regl(port, S3C2410_UCON, cfg->ucon); + wr_regl(port, S3C2410_ULCON, cfg->ulcon); + + /* reset both fifos */ + + wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); + wr_regl(port, S3C2410_UFCON, cfg->ufcon); + + return 0; +} + +static struct s3c24xx_uart_info s3c2400_uart_inf = { + .name = "Samsung S3C2400 UART", + .type = PORT_S3C2400, + .fifosize = 16, + .rx_fifomask = S3C2410_UFSTAT_RXMASK, + .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT, + .rx_fifofull = S3C2410_UFSTAT_RXFULL, + .tx_fifofull = S3C2410_UFSTAT_TXFULL, + .tx_fifomask = S3C2410_UFSTAT_TXMASK, + .tx_fifoshift = S3C2410_UFSTAT_TXSHIFT, + .get_clksrc = s3c2400_serial_getsource, + .set_clksrc = s3c2400_serial_setsource, + .reset_port = s3c2400_serial_resetport, +}; + +static int s3c2400_serial_probe(struct platform_device *dev) +{ + return s3c24xx_serial_probe(dev, &s3c2400_uart_inf); +} + +static struct platform_driver s3c2400_serial_driver = { + .probe = s3c2400_serial_probe, + .remove = __devexit_p(s3c24xx_serial_remove), + .driver = { + .name = "s3c2400-uart", + .owner = THIS_MODULE, + }, +}; + +s3c24xx_console_init(&s3c2400_serial_driver, &s3c2400_uart_inf); + +static inline int s3c2400_serial_init(void) +{ + return s3c24xx_serial_init(&s3c2400_serial_driver, &s3c2400_uart_inf); +} + +static inline void s3c2400_serial_exit(void) +{ + platform_driver_unregister(&s3c2400_serial_driver); +} + +module_init(s3c2400_serial_init); +module_exit(s3c2400_serial_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); +MODULE_DESCRIPTION("Samsung S3C2400 SoC Serial port driver"); +MODULE_ALIAS("platform:s3c2400-uart"); diff --git a/drivers/tty/serial/s3c24a0.c b/drivers/tty/serial/s3c24a0.c new file mode 100644 index 00000000000..914eff22e49 --- /dev/null +++ b/drivers/tty/serial/s3c24a0.c @@ -0,0 +1,117 @@ +/* + * Driver for Samsung S3C24A0 SoC onboard UARTs. + * + * Based on drivers/serial/s3c2410.c + * + * Author: Sandeep Patil <sandeep.patil@azingo.com> + * + * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * + * 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/module.h> +#include <linux/ioport.h> +#include <linux/platform_device.h> +#include <linux/init.h> +#include <linux/serial_core.h> +#include <linux/serial.h> +#include <linux/io.h> +#include <linux/irq.h> + +#include <mach/hardware.h> + +#include <plat/regs-serial.h> +#include <mach/regs-gpio.h> + +#include "samsung.h" + +static int s3c24a0_serial_setsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + if (strcmp(clk->name, "uclk") == 0) + ucon |= S3C2410_UCON_UCLK; + else + ucon &= ~S3C2410_UCON_UCLK; + + wr_regl(port, S3C2410_UCON, ucon); + return 0; +} + +static int s3c24a0_serial_getsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + clk->divisor = 1; + clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk"; + + return 0; +} + +static int s3c24a0_serial_resetport(struct uart_port *port, + struct s3c2410_uartcfg *cfg) +{ + dbg("s3c24a0_serial_resetport: port=%p (%08lx), cfg=%p\n", + port, port->mapbase, cfg); + + wr_regl(port, S3C2410_UCON, cfg->ucon); + wr_regl(port, S3C2410_ULCON, cfg->ulcon); + + /* reset both fifos */ + + wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); + wr_regl(port, S3C2410_UFCON, cfg->ufcon); + + return 0; +} + +static struct s3c24xx_uart_info s3c24a0_uart_inf = { + .name = "Samsung S3C24A0 UART", + .type = PORT_S3C2410, + .fifosize = 16, + .rx_fifomask = S3C24A0_UFSTAT_RXMASK, + .rx_fifoshift = S3C24A0_UFSTAT_RXSHIFT, + .rx_fifofull = S3C24A0_UFSTAT_RXFULL, + .tx_fifofull = S3C24A0_UFSTAT_TXFULL, + .tx_fifomask = S3C24A0_UFSTAT_TXMASK, + .tx_fifoshift = S3C24A0_UFSTAT_TXSHIFT, + .get_clksrc = s3c24a0_serial_getsource, + .set_clksrc = s3c24a0_serial_setsource, + .reset_port = s3c24a0_serial_resetport, +}; + +static int s3c24a0_serial_probe(struct platform_device *dev) +{ + return s3c24xx_serial_probe(dev, &s3c24a0_uart_inf); +} + +static struct platform_driver s3c24a0_serial_driver = { + .probe = s3c24a0_serial_probe, + .remove = __devexit_p(s3c24xx_serial_remove), + .driver = { + .name = "s3c24a0-uart", + .owner = THIS_MODULE, + }, +}; + +s3c24xx_console_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf); + +static int __init s3c24a0_serial_init(void) +{ + return s3c24xx_serial_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf); +} + +static void __exit s3c24a0_serial_exit(void) +{ + platform_driver_unregister(&s3c24a0_serial_driver); +} + +module_init(s3c24a0_serial_init); +module_exit(s3c24a0_serial_exit); + diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index 6ddb401552c..609a2807317 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig @@ -30,13 +30,6 @@ config PANEL_NEC_NL8048HL11_01B This NEC NL8048HL11-01B panel is TFT LCD used in the Zoom2/3/3630 sdp boards. -config PANEL_PICODLP - tristate "TI PICO DLP mini-projector" - depends on OMAP2_DSS && I2C - help - A mini-projector used in TI's SDP4430 and EVM boards - For more info please visit http://www.dlp.com/projector/ - config PANEL_TAAL tristate "Taal DSI Panel" depends on OMAP2_DSS_DSI diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile index d90f73c8716..0f601ab3abf 100644 --- a/drivers/video/omap2/displays/Makefile +++ b/drivers/video/omap2/displays/Makefile @@ -4,6 +4,5 @@ obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o obj-$(CONFIG_PANEL_TAAL) += panel-taal.o -obj-$(CONFIG_PANEL_PICODLP) += panel-picodlp.o obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c deleted file mode 100644 index 8d6190c544f..00000000000 --- a/drivers/video/omap2/displays/panel-picodlp.c +++ /dev/null @@ -1,591 +0,0 @@ -/* - * picodlp panel driver - * picodlp_i2c_driver: i2c_client driver - * - * Copyright (C) 2009-2011 Texas Instruments - * Author: Mythri P K <mythripk@ti.com> - * Mayuresh Janorkar <mayur@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, see <http://www.gnu.org/licenses/>. - */ - -#include <linux/input.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/firmware.h> -#include <linux/slab.h> -#include <linux/mutex.h> -#include <linux/i2c.h> -#include <linux/delay.h> -#include <linux/gpio.h> - -#include <video/omapdss.h> -#include <video/omap-panel-picodlp.h> - -#include "panel-picodlp.h" - -struct picodlp_data { - struct mutex lock; - struct i2c_client *picodlp_i2c_client; -}; - -static struct i2c_board_info picodlp_i2c_board_info = { - I2C_BOARD_INFO("picodlp_i2c_driver", 0x1b), -}; - -struct picodlp_i2c_data { - struct mutex xfer_lock; -}; - -static struct i2c_device_id picodlp_i2c_id[] = { - { "picodlp_i2c_driver", 0 }, -}; - -struct picodlp_i2c_command { - u8 reg; - u32 value; -}; - -static struct omap_video_timings pico_ls_timings = { - .x_res = 864, - .y_res = 480, - .hsw = 7, - .hfp = 11, - .hbp = 7, - - .pixel_clock = 19200, - - .vsw = 2, - .vfp = 3, - .vbp = 14, -}; - -static inline struct picodlp_panel_data - *get_panel_data(const struct omap_dss_device *dssdev) -{ - return (struct picodlp_panel_data *) dssdev->data; -} - -static u32 picodlp_i2c_read(struct i2c_client *client, u8 reg) -{ - u8 read_cmd[] = {READ_REG_SELECT, reg}, data[4]; - struct picodlp_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client); - struct i2c_msg msg[2]; - - mutex_lock(&picodlp_i2c_data->xfer_lock); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = 2; - msg[0].buf = read_cmd; - - msg[1].addr = client->addr; - msg[1].flags = I2C_M_RD; - msg[1].len = 4; - msg[1].buf = data; - - i2c_transfer(client->adapter, msg, 2); - mutex_unlock(&picodlp_i2c_data->xfer_lock); - return (data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24)); -} - -static int picodlp_i2c_write_block(struct i2c_client *client, - u8 *data, int len) -{ - struct i2c_msg msg; - int i, r, msg_count = 1; - - struct picodlp_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client); - - if (len < 1 || len > 32) { - dev_err(&client->dev, - "too long syn_write_block len %d\n", len); - return -EIO; - } - mutex_lock(&picodlp_i2c_data->xfer_lock); - - msg.addr = client->addr; - msg.flags = 0; - msg.len = len; - msg.buf = data; - r = i2c_transfer(client->adapter, &msg, msg_count); - mutex_unlock(&picodlp_i2c_data->xfer_lock); - - /* - * i2c_transfer returns: - * number of messages sent in case of success - * a negative error number in case of failure - */ - if (r != msg_count) - goto err; - - /* In case of success */ - for (i = 0; i < len; i++) - dev_dbg(&client->dev, - "addr %x bw 0x%02x[%d]: 0x%02x\n", - client->addr, data[0] + i, i, data[i]); - - return 0; -err: - dev_err(&client->dev, "picodlp_i2c_write error\n"); - return r; -} - -static int picodlp_i2c_write(struct i2c_client *client, u8 reg, u32 value) -{ - u8 data[5]; - int i; - - data[0] = reg; - for (i = 1; i < 5; i++) - data[i] = (value >> (32 - (i) * 8)) & 0xFF; - - return picodlp_i2c_write_block(client, data, 5); -} - -static int picodlp_i2c_write_array(struct i2c_client *client, - const struct picodlp_i2c_command commands[], - int count) -{ - int i, r = 0; - for (i = 0; i < count; i++) { - r = picodlp_i2c_write(client, commands[i].reg, - commands[i].value); - if (r) - return r; - } - return r; -} - -static int picodlp_wait_for_dma_done(struct i2c_client *client) -{ - u8 trial = 100; - - do { - msleep(1); - if (!trial--) - return -ETIMEDOUT; - } while (picodlp_i2c_read(client, MAIN_STATUS) & DMA_STATUS); - - return 0; -} - -/** - * picodlp_i2c_init: i2c_initialization routine - * client: i2c_client for communication - * - * return - * 0 : Success, no error - * error code : Failure - */ -static int picodlp_i2c_init(struct i2c_client *client) -{ - int r; - static const struct picodlp_i2c_command init_cmd_set1[] = { - {SOFT_RESET, 1}, - {DMD_PARK_TRIGGER, 1}, - {MISC_REG, 5}, - {SEQ_CONTROL, 0}, - {SEQ_VECTOR, 0x100}, - {DMD_BLOCK_COUNT, 7}, - {DMD_VCC_CONTROL, 0x109}, - {DMD_PARK_PULSE_COUNT, 0xA}, - {DMD_PARK_PULSE_WIDTH, 0xB}, - {DMD_PARK_DELAY, 0x2ED}, - {DMD_SHADOW_ENABLE, 0}, - {FLASH_OPCODE, 0xB}, - {FLASH_DUMMY_BYTES, 1}, - {FLASH_ADDR_BYTES, 3}, - {PBC_CONTROL, 0}, - {FLASH_START_ADDR, CMT_LUT_0_START_ADDR}, - {FLASH_READ_BYTES, CMT_LUT_0_SIZE}, - {CMT_SPLASH_LUT_START_ADDR, 0}, - {CMT_SPLASH_LUT_DEST_SELECT, CMT_LUT_ALL}, - {PBC_CONTROL, 1}, - }; - - static const struct picodlp_i2c_command init_cmd_set2[] = { - {PBC_CONTROL, 0}, - {CMT_SPLASH_LUT_DEST_SELECT, 0}, - {PBC_CONTROL, 0}, - {FLASH_START_ADDR, SEQUENCE_0_START_ADDR}, - {FLASH_READ_BYTES, SEQUENCE_0_SIZE}, - {SEQ_RESET_LUT_START_ADDR, 0}, - {SEQ_RESET_LUT_DEST_SELECT, SEQ_SEQ_LUT}, - {PBC_CONTROL, 1}, - }; - - static const struct picodlp_i2c_command init_cmd_set3[] = { - {PBC_CONTROL, 0}, - {SEQ_RESET_LUT_DEST_SELECT, 0}, - {PBC_CONTROL, 0}, - {FLASH_START_ADDR, DRC_TABLE_0_START_ADDR}, - {FLASH_READ_BYTES, DRC_TABLE_0_SIZE}, - {SEQ_RESET_LUT_START_ADDR, 0}, - {SEQ_RESET_LUT_DEST_SELECT, SEQ_DRC_LUT_ALL}, - {PBC_CONTROL, 1}, - }; - - static const struct picodlp_i2c_command init_cmd_set4[] = { - {PBC_CONTROL, 0}, - {SEQ_RESET_LUT_DEST_SELECT, 0}, - {SDC_ENABLE, 1}, - {AGC_CTRL, 7}, - {CCA_C1A, 0x100}, - {CCA_C1B, 0x0}, - {CCA_C1C, 0x0}, - {CCA_C2A, 0x0}, - {CCA_C2B, 0x100}, - {CCA_C2C, 0x0}, - {CCA_C3A, 0x0}, - {CCA_C3B, 0x0}, - {CCA_C3C, 0x100}, - {CCA_C7A, 0x100}, - {CCA_C7B, 0x100}, - {CCA_C7C, 0x100}, - {CCA_ENABLE, 1}, - {CPU_IF_MODE, 1}, - {SHORT_FLIP, 1}, - {CURTAIN_CONTROL, 0}, - {DMD_PARK_TRIGGER, 0}, - {R_DRIVE_CURRENT, 0x298}, - {G_DRIVE_CURRENT, 0x298}, - {B_DRIVE_CURRENT, 0x298}, - {RGB_DRIVER_ENABLE, 7}, - {SEQ_CONTROL, 0}, - {ACTGEN_CONTROL, 0x10}, - {SEQUENCE_MODE, SEQ_LOCK}, - {DATA_FORMAT, RGB888}, - {INPUT_RESOLUTION, WVGA_864_LANDSCAPE}, - {INPUT_SOURCE, PARALLEL_RGB}, - {CPU_IF_SYNC_METHOD, 1}, - {SEQ_CONTROL, 1} - }; - - r = picodlp_i2c_write_array(client, init_cmd_set1, - ARRAY_SIZE(init_cmd_set1)); - if (r) - return r; - - r = picodlp_wait_for_dma_done(client); - if (r) - return r; - - r = picodlp_i2c_write_array(client, init_cmd_set2, - ARRAY_SIZE(init_cmd_set2)); - if (r) - return r; - - r = picodlp_wait_for_dma_done(client); - if (r) - return r; - - r = picodlp_i2c_write_array(client, init_cmd_set3, - ARRAY_SIZE(init_cmd_set3)); - if (r) - return r; - - r = picodlp_wait_for_dma_done(client); - if (r) - return r; - - r = picodlp_i2c_write_array(client, init_cmd_set4, - ARRAY_SIZE(init_cmd_set4)); - if (r) - return r; - - return 0; -} - -static int picodlp_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct picodlp_i2c_data *picodlp_i2c_data; - - picodlp_i2c_data = kzalloc(sizeof(struct picodlp_i2c_data), GFP_KERNEL); - - if (!picodlp_i2c_data) - return -ENOMEM; - - mutex_init(&picodlp_i2c_data->xfer_lock); - i2c_set_clientdata(client, picodlp_i2c_data); - - return 0; -} - -static int picodlp_i2c_remove(struct i2c_client *client) -{ - struct picodlp_i2c_data *picodlp_i2c_data = - i2c_get_clientdata(client); - kfree(picodlp_i2c_data); - return 0; -} - -static struct i2c_driver picodlp_i2c_driver = { - .driver = { - .name = "picodlp_i2c_driver", - }, - .probe = picodlp_i2c_probe, - .remove = picodlp_i2c_remove, - .id_table = picodlp_i2c_id, -}; - -static int picodlp_panel_power_on(struct omap_dss_device *dssdev) -{ - int r, trial = 100; - struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); - struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); - - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) - return r; - } - - gpio_set_value(picodlp_pdata->pwrgood_gpio, 0); - msleep(1); - gpio_set_value(picodlp_pdata->pwrgood_gpio, 1); - - while (!gpio_get_value(picodlp_pdata->emu_done_gpio)) { - if (!trial--) { - dev_err(&dssdev->dev, "emu_done signal not" - " going high\n"); - return -ETIMEDOUT; - } - msleep(5); - } - /* - * As per dpp2600 programming guide, - * it is required to sleep for 510ms after emu_done signal goes high - * then only i2c commands can be successfully sent to dpp2600 - */ - msleep(510); - if (omapdss_dpi_display_enable(dssdev)) { - dev_err(&dssdev->dev, "failed to enable DPI\n"); - goto err1; - } - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - r = picodlp_i2c_init(picod->picodlp_i2c_client); - if (r) - goto err; - - return r; -err: - omapdss_dpi_display_disable(dssdev); -err1: - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - - return r; -} - -static void picodlp_panel_power_off(struct omap_dss_device *dssdev) -{ - struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); - - omapdss_dpi_display_disable(dssdev); - - gpio_set_value(picodlp_pdata->emu_done_gpio, 0); - gpio_set_value(picodlp_pdata->pwrgood_gpio, 0); - - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); -} - -static int picodlp_panel_probe(struct omap_dss_device *dssdev) -{ - struct picodlp_data *picod; - struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); - struct i2c_adapter *adapter; - struct i2c_client *picodlp_i2c_client; - int r = 0, picodlp_adapter_id; - - dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_ONOFF | - OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IVS; - dssdev->panel.acb = 0x0; - dssdev->panel.timings = pico_ls_timings; - - picod = kzalloc(sizeof(struct picodlp_data), GFP_KERNEL); - if (!picod) - return -ENOMEM; - - mutex_init(&picod->lock); - - picodlp_adapter_id = picodlp_pdata->picodlp_adapter_id; - - adapter = i2c_get_adapter(picodlp_adapter_id); - if (!adapter) { - dev_err(&dssdev->dev, "can't get i2c adapter\n"); - r = -ENODEV; - goto err; - } - - picodlp_i2c_client = i2c_new_device(adapter, &picodlp_i2c_board_info); - if (!picodlp_i2c_client) { - dev_err(&dssdev->dev, "can't add i2c device::" - " picodlp_i2c_client is NULL\n"); - r = -ENODEV; - goto err; - } - - picod->picodlp_i2c_client = picodlp_i2c_client; - - dev_set_drvdata(&dssdev->dev, picod); - return r; -err: - kfree(picod); - return r; -} - -static void picodlp_panel_remove(struct omap_dss_device *dssdev) -{ - struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); - - i2c_unregister_device(picod->picodlp_i2c_client); - dev_set_drvdata(&dssdev->dev, NULL); - dev_dbg(&dssdev->dev, "removing picodlp panel\n"); - - kfree(picod); -} - -static int picodlp_panel_enable(struct omap_dss_device *dssdev) -{ - struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); - int r; - - dev_dbg(&dssdev->dev, "enabling picodlp panel\n"); - - mutex_lock(&picod->lock); - if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { - mutex_unlock(&picod->lock); - return -EINVAL; - } - - r = picodlp_panel_power_on(dssdev); - mutex_unlock(&picod->lock); - - return r; -} - -static void picodlp_panel_disable(struct omap_dss_device *dssdev) -{ - struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); - - mutex_lock(&picod->lock); - /* Turn off DLP Power */ - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) - picodlp_panel_power_off(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; - mutex_unlock(&picod->lock); - - dev_dbg(&dssdev->dev, "disabling picodlp panel\n"); -} - -static int picodlp_panel_suspend(struct omap_dss_device *dssdev) -{ - struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); - - mutex_lock(&picod->lock); - /* Turn off DLP Power */ - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { - mutex_unlock(&picod->lock); - dev_err(&dssdev->dev, "unable to suspend picodlp panel," - " panel is not ACTIVE\n"); - return -EINVAL; - } - - picodlp_panel_power_off(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - mutex_unlock(&picod->lock); - - dev_dbg(&dssdev->dev, "suspending picodlp panel\n"); - return 0; -} - -static int picodlp_panel_resume(struct omap_dss_device *dssdev) -{ - struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); - int r; - - mutex_lock(&picod->lock); - if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { - mutex_unlock(&picod->lock); - dev_err(&dssdev->dev, "unable to resume picodlp panel," - " panel is not ACTIVE\n"); - return -EINVAL; - } - - r = picodlp_panel_power_on(dssdev); - mutex_unlock(&picod->lock); - dev_dbg(&dssdev->dev, "resuming picodlp panel\n"); - return r; -} - -static void picodlp_get_resolution(struct omap_dss_device *dssdev, - u16 *xres, u16 *yres) -{ - *xres = dssdev->panel.timings.x_res; - *yres = dssdev->panel.timings.y_res; -} - -static struct omap_dss_driver picodlp_driver = { - .probe = picodlp_panel_probe, - .remove = picodlp_panel_remove, - - .enable = picodlp_panel_enable, - .disable = picodlp_panel_disable, - - .get_resolution = picodlp_get_resolution, - - .suspend = picodlp_panel_suspend, - .resume = picodlp_panel_resume, - - .driver = { - .name = "picodlp_panel", - .owner = THIS_MODULE, - }, -}; - -static int __init picodlp_init(void) -{ - int r = 0; - - r = i2c_add_driver(&picodlp_i2c_driver); - if (r) { - printk(KERN_WARNING "picodlp_i2c_driver" \ - " registration failed\n"); - return r; - } - - r = omap_dss_register_driver(&picodlp_driver); - if (r) - i2c_del_driver(&picodlp_i2c_driver); - - return r; -} - -static void __exit picodlp_exit(void) -{ - i2c_del_driver(&picodlp_i2c_driver); - omap_dss_unregister_driver(&picodlp_driver); -} - -module_init(picodlp_init); -module_exit(picodlp_exit); - -MODULE_AUTHOR("Mythri P K <mythripk@ti.com>"); -MODULE_DESCRIPTION("picodlp driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/omap2/displays/panel-picodlp.h b/drivers/video/omap2/displays/panel-picodlp.h deleted file mode 100644 index a34b431a726..00000000000 --- a/drivers/video/omap2/displays/panel-picodlp.h +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Header file required by picodlp panel driver - * - * Copyright (C) 2009-2011 Texas Instruments - * Author: Mythri P K <mythripk@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, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef __OMAP2_DISPLAY_PANEL_PICODLP_H -#define __OMAP2_DISPLAY_PANEL_PICODLP_H - -/* Commands used for configuring picodlp panel */ - -#define MAIN_STATUS 0x03 -#define PBC_CONTROL 0x08 -#define INPUT_SOURCE 0x0B -#define INPUT_RESOLUTION 0x0C -#define DATA_FORMAT 0x0D -#define IMG_ROTATION 0x0E -#define LONG_FLIP 0x0F -#define SHORT_FLIP 0x10 -#define TEST_PAT_SELECT 0x11 -#define R_DRIVE_CURRENT 0x12 -#define G_DRIVE_CURRENT 0x13 -#define B_DRIVE_CURRENT 0x14 -#define READ_REG_SELECT 0x15 -#define RGB_DRIVER_ENABLE 0x16 - -#define CPU_IF_MODE 0x18 -#define FRAME_RATE 0x19 -#define CPU_IF_SYNC_METHOD 0x1A -#define CPU_IF_SOF 0x1B -#define CPU_IF_EOF 0x1C -#define CPU_IF_SLEEP 0x1D - -#define SEQUENCE_MODE 0x1E -#define SOFT_RESET 0x1F -#define FRONT_END_RESET 0x21 -#define AUTO_PWR_ENABLE 0x22 - -#define VSYNC_LINE_DELAY 0x23 -#define CPU_PI_HORIZ_START 0x24 -#define CPU_PI_VERT_START 0x25 -#define CPU_PI_HORIZ_WIDTH 0x26 -#define CPU_PI_VERT_HEIGHT 0x27 - -#define PIXEL_MASK_CROP 0x28 -#define CROP_FIRST_LINE 0x29 -#define CROP_LAST_LINE 0x2A -#define CROP_FIRST_PIXEL 0x2B -#define CROP_LAST_PIXEL 0x2C -#define DMD_PARK_TRIGGER 0x2D - -#define MISC_REG 0x30 - -/* AGC registers */ -#define AGC_CTRL 0x50 -#define AGC_CLIPPED_PIXS 0x55 -#define AGC_BRIGHT_PIXS 0x56 -#define AGC_BG_PIXS 0x57 -#define AGC_SAFETY_MARGIN 0x17 - -/* Color Coordinate Adjustment registers */ -#define CCA_ENABLE 0x5E -#define CCA_C1A 0x5F -#define CCA_C1B 0x60 -#define CCA_C1C 0x61 -#define CCA_C2A 0x62 -#define CCA_C2B 0x63 -#define CCA_C2C 0x64 -#define CCA_C3A 0x65 -#define CCA_C3B 0x66 -#define CCA_C3C 0x67 -#define CCA_C7A 0x71 -#define CCA_C7B 0x72 -#define CCA_C7C 0x73 - -/** - * DLP Pico Processor 2600 comes with flash - * We can do DMA operations from flash for accessing Look Up Tables - */ -#define DMA_STATUS 0x100 -#define FLASH_ADDR_BYTES 0x74 -#define FLASH_DUMMY_BYTES 0x75 -#define FLASH_WRITE_BYTES 0x76 -#define FLASH_READ_BYTES 0x77 -#define FLASH_OPCODE 0x78 -#define FLASH_START_ADDR 0x79 -#define FLASH_DUMMY2 0x7A -#define FLASH_WRITE_DATA 0x7B - -#define TEMPORAL_DITH_DISABLE 0x7E -#define SEQ_CONTROL 0x82 -#define SEQ_VECTOR 0x83 - -/* DMD is Digital Micromirror Device */ -#define DMD_BLOCK_COUNT 0x84 -#define DMD_VCC_CONTROL 0x86 -#define DMD_PARK_PULSE_COUNT 0x87 -#define DMD_PARK_PULSE_WIDTH 0x88 -#define DMD_PARK_DELAY 0x89 -#define DMD_SHADOW_ENABLE 0x8E -#define SEQ_STATUS 0x8F -#define FLASH_CLOCK_CONTROL 0x98 -#define DMD_PARK 0x2D - -#define SDRAM_BIST_ENABLE 0x46 -#define DDR_DRIVER_STRENGTH 0x9A -#define SDC_ENABLE 0x9D -#define SDC_BUFF_SWAP_DISABLE 0xA3 -#define CURTAIN_CONTROL 0xA6 -#define DDR_BUS_SWAP_ENABLE 0xA7 -#define DMD_TRC_ENABLE 0xA8 -#define DMD_BUS_SWAP_ENABLE 0xA9 - -#define ACTGEN_ENABLE 0xAE -#define ACTGEN_CONTROL 0xAF -#define ACTGEN_HORIZ_BP 0xB0 -#define ACTGEN_VERT_BP 0xB1 - -/* Look Up Table access */ -#define CMT_SPLASH_LUT_START_ADDR 0xFA -#define CMT_SPLASH_LUT_DEST_SELECT 0xFB -#define CMT_SPLASH_LUT_DATA 0xFC -#define SEQ_RESET_LUT_START_ADDR 0xFD -#define SEQ_RESET_LUT_DEST_SELECT 0xFE -#define SEQ_RESET_LUT_DATA 0xFF - -/* Input source definitions */ -#define PARALLEL_RGB 0 -#define INT_TEST_PATTERN 1 -#define SPLASH_SCREEN 2 -#define CPU_INTF 3 -#define BT656 4 - -/* Standard input resolution definitions */ -#define QWVGA_LANDSCAPE 3 /* (427h*240v) */ -#define WVGA_864_LANDSCAPE 21 /* (864h*480v) */ -#define WVGA_DMD_OPTICAL_TEST 35 /* (608h*684v) */ - -/* Standard data format definitions */ -#define RGB565 0 -#define RGB666 1 -#define RGB888 2 - -/* Test Pattern definitions */ -#define TPG_CHECKERBOARD 0 -#define TPG_BLACK 1 -#define TPG_WHITE 2 -#define TPG_RED 3 -#define TPG_BLUE 4 -#define TPG_GREEN 5 -#define TPG_VLINES_BLACK 6 -#define TPG_HLINES_BLACK 7 -#define TPG_VLINES_ALT 8 -#define TPG_HLINES_ALT 9 -#define TPG_DIAG_LINES 10 -#define TPG_GREYRAMP_VERT 11 -#define TPG_GREYRAMP_HORIZ 12 -#define TPG_ANSI_CHECKERBOARD 13 - -/* sequence mode definitions */ -#define SEQ_FREE_RUN 0 -#define SEQ_LOCK 1 - -/* curtain color definitions */ -#define CURTAIN_BLACK 0 -#define CURTAIN_RED 1 -#define CURTAIN_GREEN 2 -#define CURTAIN_BLUE 3 -#define CURTAIN_YELLOW 4 -#define CURTAIN_MAGENTA 5 -#define CURTAIN_CYAN 6 -#define CURTAIN_WHITE 7 - -/* LUT definitions */ -#define CMT_LUT_NONE 0 -#define CMT_LUT_GREEN 1 -#define CMT_LUT_RED 2 -#define CMT_LUT_BLUE 3 -#define CMT_LUT_ALL 4 -#define SPLASH_LUT 5 - -#define SEQ_LUT_NONE 0 -#define SEQ_DRC_LUT_0 1 -#define SEQ_DRC_LUT_1 2 -#define SEQ_DRC_LUT_2 3 -#define SEQ_DRC_LUT_3 4 -#define SEQ_SEQ_LUT 5 -#define SEQ_DRC_LUT_ALL 6 -#define WPC_PROGRAM_LUT 7 - -#define BITSTREAM_START_ADDR 0x00000000 -#define BITSTREAM_SIZE 0x00040000 - -#define WPC_FW_0_START_ADDR 0x00040000 -#define WPC_FW_0_SIZE 0x00000ce8 - -#define SEQUENCE_0_START_ADDR 0x00044000 -#define SEQUENCE_0_SIZE 0x00001000 - -#define SEQUENCE_1_START_ADDR 0x00045000 -#define SEQUENCE_1_SIZE 0x00000d10 - -#define SEQUENCE_2_START_ADDR 0x00046000 -#define SEQUENCE_2_SIZE 0x00000d10 - -#define SEQUENCE_3_START_ADDR 0x00047000 -#define SEQUENCE_3_SIZE 0x00000d10 - -#define SEQUENCE_4_START_ADDR 0x00048000 -#define SEQUENCE_4_SIZE 0x00000d10 - -#define SEQUENCE_5_START_ADDR 0x00049000 -#define SEQUENCE_5_SIZE 0x00000d10 - -#define SEQUENCE_6_START_ADDR 0x0004a000 -#define SEQUENCE_6_SIZE 0x00000d10 - -#define CMT_LUT_0_START_ADDR 0x0004b200 -#define CMT_LUT_0_SIZE 0x00000600 - -#define CMT_LUT_1_START_ADDR 0x0004b800 -#define CMT_LUT_1_SIZE 0x00000600 - -#define CMT_LUT_2_START_ADDR 0x0004be00 -#define CMT_LUT_2_SIZE 0x00000600 - -#define CMT_LUT_3_START_ADDR 0x0004c400 -#define CMT_LUT_3_SIZE 0x00000600 - -#define CMT_LUT_4_START_ADDR 0x0004ca00 -#define CMT_LUT_4_SIZE 0x00000600 - -#define CMT_LUT_5_START_ADDR 0x0004d000 -#define CMT_LUT_5_SIZE 0x00000600 - -#define CMT_LUT_6_START_ADDR 0x0004d600 -#define CMT_LUT_6_SIZE 0x00000600 - -#define DRC_TABLE_0_START_ADDR 0x0004dc00 -#define DRC_TABLE_0_SIZE 0x00000100 - -#define SPLASH_0_START_ADDR 0x0004dd00 -#define SPLASH_0_SIZE 0x00032280 - -#define SEQUENCE_7_START_ADDR 0x00080000 -#define SEQUENCE_7_SIZE 0x00000d10 - -#define SEQUENCE_8_START_ADDR 0x00081800 -#define SEQUENCE_8_SIZE 0x00000d10 - -#define SEQUENCE_9_START_ADDR 0x00083000 -#define SEQUENCE_9_SIZE 0x00000d10 - -#define CMT_LUT_7_START_ADDR 0x0008e000 -#define CMT_LUT_7_SIZE 0x00000600 - -#define CMT_LUT_8_START_ADDR 0x0008e800 -#define CMT_LUT_8_SIZE 0x00000600 - -#define CMT_LUT_9_START_ADDR 0x0008f000 -#define CMT_LUT_9_SIZE 0x00000600 - -#define SPLASH_1_START_ADDR 0x0009a000 -#define SPLASH_1_SIZE 0x00032280 - -#define SPLASH_2_START_ADDR 0x000cd000 -#define SPLASH_2_SIZE 0x00032280 - -#define SPLASH_3_START_ADDR 0x00100000 -#define SPLASH_3_SIZE 0x00032280 - -#define OPT_SPLASH_0_START_ADDR 0x00134000 -#define OPT_SPLASH_0_SIZE 0x000cb100 - -#endif diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 4cb0449d509..fdd5d4ae437 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -504,18 +504,14 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev) return 0; r = omapdss_dsi_display_enable(dssdev); - if (r) { - dev_err(&dssdev->dev, "failed to enable DSI\n"); - goto err1; - } + if (r) + goto err; omapdss_dsi_vc_enable_hs(dssdev, td->channel, true); r = _taal_enable_te(dssdev, true); - if (r) { - dev_err(&dssdev->dev, "failed to re-enable TE"); - goto err2; - } + if (r) + goto err; enable_irq(gpio_to_irq(panel_data->ext_te_gpio)); @@ -525,15 +521,13 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev) return 0; -err2: - dev_err(&dssdev->dev, "failed to exit ULPS"); - +err: + dev_err(&dssdev->dev, "exit ULPS failed"); r = taal_panel_reset(dssdev); - if (!r) { - enable_irq(gpio_to_irq(panel_data->ext_te_gpio)); - td->ulps_enabled = false; - } -err1: + + enable_irq(gpio_to_irq(panel_data->ext_te_gpio)); + td->ulps_enabled = false; + taal_queue_ulps_work(dssdev); return r; @@ -1323,11 +1317,8 @@ static void taal_disable(struct omap_dss_device *dssdev) dsi_bus_lock(dssdev); if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - int r; - - r = taal_wake_up(dssdev); - if (!r) - taal_power_off(dssdev); + taal_wake_up(dssdev); + taal_power_off(dssdev); } dsi_bus_unlock(dssdev); @@ -1906,6 +1897,20 @@ err: mutex_unlock(&td->lock); } +static int taal_set_update_mode(struct omap_dss_device *dssdev, + enum omap_dss_update_mode mode) +{ + if (mode != OMAP_DSS_UPDATE_MANUAL) + return -EINVAL; + return 0; +} + +static enum omap_dss_update_mode taal_get_update_mode( + struct omap_dss_device *dssdev) +{ + return OMAP_DSS_UPDATE_MANUAL; +} + static struct omap_dss_driver taal_driver = { .probe = taal_probe, .remove = __exit_p(taal_remove), @@ -1915,6 +1920,9 @@ static struct omap_dss_driver taal_driver = { .suspend = taal_suspend, .resume = taal_resume, + .set_update_mode = taal_set_update_mode, + .get_update_mode = taal_get_update_mode, + .update = taal_update, .sync = taal_sync, diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index 0d12524db14..6b3e2da1141 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -117,6 +117,18 @@ config OMAP2_DSS_MIN_FCK_PER_PCK Max FCK is 173MHz, so this doesn't work if your PCK is very high. +config OMAP2_DSS_SLEEP_BEFORE_RESET + bool "Sleep 50ms before DSS reset" + default y + help + For some unknown reason we may get SYNC_LOST errors from the display + subsystem at initialization time if we don't sleep before resetting + the DSS. See the source (dss.c) for more comments. + + However, 50ms is quite long time to sleep, and with some + configurations the SYNC_LOST may never happen, so the sleep can + be disabled here. + config OMAP2_DSS_SLEEP_AFTER_VENC_RESET bool "Sleep 20ms after VENC reset" default y diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index f0bae6d5340..3da426719dd 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -183,11 +183,8 @@ static int omap_dss_probe(struct platform_device *pdev) goto err_dss; } - r = dispc_init_platform_driver(); - if (r) { - DSSERR("Failed to initialize dispc platform driver\n"); - goto err_dispc; - } + /* keep clocks enabled to prevent context saves/restores during init */ + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); r = rfbi_init_platform_driver(); if (r) { @@ -195,6 +192,12 @@ static int omap_dss_probe(struct platform_device *pdev) goto err_rfbi; } + r = dispc_init_platform_driver(); + if (r) { + DSSERR("Failed to initialize dispc platform driver\n"); + goto err_dispc; + } + r = venc_init_platform_driver(); if (r) { DSSERR("Failed to initialize venc platform driver\n"); @@ -235,6 +238,8 @@ static int omap_dss_probe(struct platform_device *pdev) pdata->default_device = dssdev; } + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + return 0; err_register: diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index eac768ff2d3..7a9a2e7d968 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -33,8 +33,6 @@ #include <linux/workqueue.h> #include <linux/hardirq.h> #include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> #include <plat/sram.h> #include <plat/clock.h> @@ -94,11 +92,7 @@ struct dispc_irq_stats { static struct { struct platform_device *pdev; void __iomem *base; - - int ctx_loss_cnt; - int irq; - struct clk *dss_clk; u32 fifo_size[3]; @@ -108,7 +102,6 @@ static struct { u32 error_irqs; struct work_struct error_work; - bool ctx_valid; u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS @@ -141,34 +134,18 @@ static inline u32 dispc_read_reg(const u16 idx) return __raw_readl(dispc.base + idx); } -static int dispc_get_ctx_loss_count(void) -{ - struct device *dev = &dispc.pdev->dev; - struct omap_display_platform_data *pdata = dev->platform_data; - struct omap_dss_board_info *board_data = pdata->board_data; - int cnt; - - if (!board_data->get_context_loss_count) - return -ENOENT; - - cnt = board_data->get_context_loss_count(dev); - - WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt); - - return cnt; -} - #define SR(reg) \ dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg) #define RR(reg) \ dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)]) -static void dispc_save_context(void) +void dispc_save_context(void) { int i; + if (cpu_is_omap24xx()) + return; - DSSDBG("dispc_save_context\n"); - + SR(SYSCONFIG); SR(IRQENABLE); SR(CONTROL); SR(CONFIG); @@ -181,8 +158,7 @@ static void dispc_save_context(void) SR(TIMING_V(OMAP_DSS_CHANNEL_LCD)); SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD)); SR(DIVISORo(OMAP_DSS_CHANNEL_LCD)); - if (dss_has_feature(FEAT_GLOBAL_ALPHA)) - SR(GLOBAL_ALPHA); + SR(GLOBAL_ALPHA); SR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); if (dss_has_feature(FEAT_MGR_LCD2)) { @@ -212,25 +188,20 @@ static void dispc_save_context(void) SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); - if (dss_has_feature(FEAT_CPR)) { - SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); - SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); - SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); - } + SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); + SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); + SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); if (dss_has_feature(FEAT_MGR_LCD2)) { - if (dss_has_feature(FEAT_CPR)) { - SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); - SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); - SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); - } + SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); + SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); + SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); } - if (dss_has_feature(FEAT_PRELOAD)) - SR(OVL_PRELOAD(OMAP_DSS_GFX)); + SR(OVL_PRELOAD(OMAP_DSS_GFX)); /* VID1 */ SR(OVL_BA0(OMAP_DSS_VIDEO1)); @@ -255,10 +226,8 @@ static void dispc_save_context(void) for (i = 0; i < 5; i++) SR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i)); - if (dss_has_feature(FEAT_FIR_COEF_V)) { - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); - } + for (i = 0; i < 8; i++) + SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { SR(OVL_BA0_UV(OMAP_DSS_VIDEO1)); @@ -279,8 +248,7 @@ static void dispc_save_context(void) if (dss_has_feature(FEAT_ATTR2)) SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1)); - if (dss_has_feature(FEAT_PRELOAD)) - SR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); + SR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); /* VID2 */ SR(OVL_BA0(OMAP_DSS_VIDEO2)); @@ -305,10 +273,8 @@ static void dispc_save_context(void) for (i = 0; i < 5; i++) SR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i)); - if (dss_has_feature(FEAT_FIR_COEF_V)) { - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); - } + for (i = 0; i < 8; i++) + SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { SR(OVL_BA0_UV(OMAP_DSS_VIDEO2)); @@ -329,35 +295,16 @@ static void dispc_save_context(void) if (dss_has_feature(FEAT_ATTR2)) SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); - if (dss_has_feature(FEAT_PRELOAD)) - SR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); + SR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); if (dss_has_feature(FEAT_CORE_CLK_DIV)) SR(DIVISOR); - - dispc.ctx_loss_cnt = dispc_get_ctx_loss_count(); - dispc.ctx_valid = true; - - DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt); } -static void dispc_restore_context(void) +void dispc_restore_context(void) { - int i, ctx; - - DSSDBG("dispc_restore_context\n"); - - if (!dispc.ctx_valid) - return; - - ctx = dispc_get_ctx_loss_count(); - - if (ctx >= 0 && ctx == dispc.ctx_loss_cnt) - return; - - DSSDBG("ctx_loss_count: saved %d, current %d\n", - dispc.ctx_loss_cnt, ctx); - + int i; + RR(SYSCONFIG); /*RR(IRQENABLE);*/ /*RR(CONTROL);*/ RR(CONFIG); @@ -370,8 +317,7 @@ static void dispc_restore_context(void) RR(TIMING_V(OMAP_DSS_CHANNEL_LCD)); RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD)); RR(DIVISORo(OMAP_DSS_CHANNEL_LCD)); - if (dss_has_feature(FEAT_GLOBAL_ALPHA)) - RR(GLOBAL_ALPHA); + RR(GLOBAL_ALPHA); RR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); if (dss_has_feature(FEAT_MGR_LCD2)) { @@ -401,25 +347,20 @@ static void dispc_restore_context(void) RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); - if (dss_has_feature(FEAT_CPR)) { - RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); - RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); - RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); - } + RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); + RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); + RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); if (dss_has_feature(FEAT_MGR_LCD2)) { RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); - if (dss_has_feature(FEAT_CPR)) { - RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); - RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); - RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); - } + RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); + RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); + RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); } - if (dss_has_feature(FEAT_PRELOAD)) - RR(OVL_PRELOAD(OMAP_DSS_GFX)); + RR(OVL_PRELOAD(OMAP_DSS_GFX)); /* VID1 */ RR(OVL_BA0(OMAP_DSS_VIDEO1)); @@ -444,10 +385,8 @@ static void dispc_restore_context(void) for (i = 0; i < 5; i++) RR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i)); - if (dss_has_feature(FEAT_FIR_COEF_V)) { - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); - } + for (i = 0; i < 8; i++) + RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { RR(OVL_BA0_UV(OMAP_DSS_VIDEO1)); @@ -468,8 +407,7 @@ static void dispc_restore_context(void) if (dss_has_feature(FEAT_ATTR2)) RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1)); - if (dss_has_feature(FEAT_PRELOAD)) - RR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); + RR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); /* VID2 */ RR(OVL_BA0(OMAP_DSS_VIDEO2)); @@ -494,10 +432,8 @@ static void dispc_restore_context(void) for (i = 0; i < 5; i++) RR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i)); - if (dss_has_feature(FEAT_FIR_COEF_V)) { - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); - } + for (i = 0; i < 8; i++) + RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { RR(OVL_BA0_UV(OMAP_DSS_VIDEO2)); @@ -518,8 +454,7 @@ static void dispc_restore_context(void) if (dss_has_feature(FEAT_ATTR2)) RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); - if (dss_has_feature(FEAT_PRELOAD)) - RR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); + RR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); if (dss_has_feature(FEAT_CORE_CLK_DIV)) RR(DIVISOR); @@ -536,35 +471,19 @@ static void dispc_restore_context(void) * the context is fully restored */ RR(IRQENABLE); - - DSSDBG("context restored\n"); } #undef SR #undef RR -int dispc_runtime_get(void) -{ - int r; - - DSSDBG("dispc_runtime_get\n"); - - r = pm_runtime_get_sync(&dispc.pdev->dev); - WARN_ON(r < 0); - return r < 0 ? r : 0; -} - -void dispc_runtime_put(void) +static inline void enable_clocks(bool enable) { - int r; - - DSSDBG("dispc_runtime_put\n"); - - r = pm_runtime_put(&dispc.pdev->dev); - WARN_ON(r < 0); + if (enable) + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); + else + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); } - bool dispc_go_busy(enum omap_channel channel) { int bit; @@ -586,6 +505,8 @@ void dispc_go(enum omap_channel channel) int bit; bool enable_bit, go_bit; + enable_clocks(1); + if (channel == OMAP_DSS_CHANNEL_LCD || channel == OMAP_DSS_CHANNEL_LCD2) bit = 0; /* LCDENABLE */ @@ -599,7 +520,7 @@ void dispc_go(enum omap_channel channel) enable_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1; if (!enable_bit) - return; + goto end; if (channel == OMAP_DSS_CHANNEL_LCD || channel == OMAP_DSS_CHANNEL_LCD2) @@ -614,7 +535,7 @@ void dispc_go(enum omap_channel channel) if (go_bit) { DSSERR("GO bit not down for channel %d\n", channel); - return; + goto end; } DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : @@ -624,6 +545,8 @@ void dispc_go(enum omap_channel channel) REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit); else REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit); +end: + enable_clocks(0); } static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value) @@ -997,7 +920,7 @@ static void _dispc_set_color_mode(enum omap_plane plane, REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); } -void dispc_set_channel_out(enum omap_plane plane, +static void _dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel) { int shift; @@ -1050,6 +973,8 @@ void dispc_set_burst_size(enum omap_plane plane, int shift; u32 val; + enable_clocks(1); + switch (plane) { case OMAP_DSS_GFX: shift = 6; @@ -1066,6 +991,8 @@ void dispc_set_burst_size(enum omap_plane plane, val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); val = FLD_MOD(val, burst_size, shift+1, shift); dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); + + enable_clocks(0); } void dispc_enable_gamma_table(bool enable) @@ -1102,7 +1029,9 @@ void dispc_enable_replication(enum omap_plane plane, bool enable) else bit = 10; + enable_clocks(1); REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit); + enable_clocks(0); } void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height) @@ -1110,7 +1039,9 @@ void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height) u32 val; BUG_ON((width > (1 << 11)) || (height > (1 << 11))); val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); + enable_clocks(1); dispc_write_reg(DISPC_SIZE_MGR(channel), val); + enable_clocks(0); } void dispc_set_digit_size(u16 width, u16 height) @@ -1118,7 +1049,9 @@ void dispc_set_digit_size(u16 width, u16 height) u32 val; BUG_ON((width > (1 << 11)) || (height > (1 << 11))); val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); + enable_clocks(1); dispc_write_reg(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT), val); + enable_clocks(0); } static void dispc_read_plane_fifo_sizes(void) @@ -1127,6 +1060,8 @@ static void dispc_read_plane_fifo_sizes(void) int plane; u8 start, end; + enable_clocks(1); + dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) { @@ -1134,6 +1069,8 @@ static void dispc_read_plane_fifo_sizes(void) start, end); dispc.fifo_size[plane] = size; } + + enable_clocks(0); } u32 dispc_get_plane_fifo_size(enum omap_plane plane) @@ -1148,6 +1085,8 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high) dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end); dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end); + enable_clocks(1); + DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n", plane, REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), @@ -1159,12 +1098,18 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high) dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane), FLD_VAL(high, hi_start, hi_end) | FLD_VAL(low, lo_start, lo_end)); + + enable_clocks(0); } void dispc_enable_fifomerge(bool enable) { + enable_clocks(1); + DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled"); REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14); + + enable_clocks(0); } static void _dispc_set_fir(enum omap_plane plane, @@ -1784,7 +1729,14 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width, return dispc_pclk_rate(channel) * vf * hf; } -int dispc_setup_plane(enum omap_plane plane, +void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out) +{ + enable_clocks(1); + _dispc_set_channel_out(plane, channel_out); + enable_clocks(0); +} + +static int _dispc_setup_plane(enum omap_plane plane, u32 paddr, u16 screen_width, u16 pos_x, u16 pos_y, u16 width, u16 height, @@ -1792,7 +1744,7 @@ int dispc_setup_plane(enum omap_plane plane, enum omap_color_mode color_mode, bool ilace, enum omap_dss_rotation_type rotation_type, - u8 rotation, bool mirror, + u8 rotation, int mirror, u8 global_alpha, u8 pre_mult_alpha, enum omap_channel channel, u32 puv_addr) { @@ -1806,14 +1758,6 @@ int dispc_setup_plane(enum omap_plane plane, u16 frame_height = height; unsigned int field_offset = 0; - DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> " - "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n", - plane, paddr, screen_width, pos_x, pos_y, - width, height, - out_width, out_height, - ilace, color_mode, - rotation, mirror, channel); - if (paddr == 0) return -EINVAL; @@ -1959,13 +1903,9 @@ int dispc_setup_plane(enum omap_plane plane, return 0; } -int dispc_enable_plane(enum omap_plane plane, bool enable) +static void _dispc_enable_plane(enum omap_plane plane, bool enable) { - DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); - - return 0; } static void dispc_disable_isr(void *data, u32 mask) @@ -1989,6 +1929,8 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) int r; u32 irq; + enable_clocks(1); + /* When we disable LCD output, we need to wait until frame is done. * Otherwise the DSS is still working, and turning off the clocks * prevents DSS from going to OFF mode */ @@ -2022,6 +1964,8 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) if (r) DSSERR("failed to unregister FRAMEDONE isr\n"); } + + enable_clocks(0); } static void _enable_digit_out(bool enable) @@ -2034,8 +1978,12 @@ static void dispc_enable_digit_out(bool enable) struct completion frame_done_completion; int r; - if (REG_GET(DISPC_CONTROL, 1, 1) == enable) + enable_clocks(1); + + if (REG_GET(DISPC_CONTROL, 1, 1) == enable) { + enable_clocks(0); return; + } if (enable) { unsigned long flags; @@ -2087,6 +2035,8 @@ static void dispc_enable_digit_out(bool enable) _omap_dispc_set_irqs(); spin_unlock_irqrestore(&dispc.irq_lock, flags); } + + enable_clocks(0); } bool dispc_is_channel_enabled(enum omap_channel channel) @@ -2117,7 +2067,9 @@ void dispc_lcd_enable_signal_polarity(bool act_high) if (!dss_has_feature(FEAT_LCDENABLEPOL)) return; + enable_clocks(1); REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29); + enable_clocks(0); } void dispc_lcd_enable_signal(bool enable) @@ -2125,7 +2077,9 @@ void dispc_lcd_enable_signal(bool enable) if (!dss_has_feature(FEAT_LCDENABLESIGNAL)) return; + enable_clocks(1); REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28); + enable_clocks(0); } void dispc_pck_free_enable(bool enable) @@ -2133,15 +2087,19 @@ void dispc_pck_free_enable(bool enable) if (!dss_has_feature(FEAT_PCKFREEENABLE)) return; + enable_clocks(1); REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27); + enable_clocks(0); } void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable) { + enable_clocks(1); if (channel == OMAP_DSS_CHANNEL_LCD2) REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16); else REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16); + enable_clocks(0); } @@ -2164,21 +2122,27 @@ void dispc_set_lcd_display_type(enum omap_channel channel, return; } + enable_clocks(1); if (channel == OMAP_DSS_CHANNEL_LCD2) REG_FLD_MOD(DISPC_CONTROL2, mode, 3, 3); else REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3); + enable_clocks(0); } void dispc_set_loadmode(enum omap_dss_load_mode mode) { + enable_clocks(1); REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1); + enable_clocks(0); } void dispc_set_default_color(enum omap_channel channel, u32 color) { + enable_clocks(1); dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); + enable_clocks(0); } u32 dispc_get_default_color(enum omap_channel channel) @@ -2189,7 +2153,9 @@ u32 dispc_get_default_color(enum omap_channel channel) channel != OMAP_DSS_CHANNEL_LCD && channel != OMAP_DSS_CHANNEL_LCD2); + enable_clocks(1); l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel)); + enable_clocks(0); return l; } @@ -2198,6 +2164,7 @@ void dispc_set_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type type, u32 trans_key) { + enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, type, 11, 11); else if (ch == OMAP_DSS_CHANNEL_DIGIT) @@ -2206,12 +2173,14 @@ void dispc_set_trans_key(enum omap_channel ch, REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11); dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); + enable_clocks(0); } void dispc_get_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type *type, u32 *trans_key) { + enable_clocks(1); if (type) { if (ch == OMAP_DSS_CHANNEL_LCD) *type = REG_GET(DISPC_CONFIG, 11, 11); @@ -2225,28 +2194,33 @@ void dispc_get_trans_key(enum omap_channel ch, if (trans_key) *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch)); + enable_clocks(0); } void dispc_enable_trans_key(enum omap_channel ch, bool enable) { + enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); else if (ch == OMAP_DSS_CHANNEL_DIGIT) REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12); else /* OMAP_DSS_CHANNEL_LCD2 */ REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10); + enable_clocks(0); } void dispc_enable_alpha_blending(enum omap_channel ch, bool enable) { if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) return; + enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18); else if (ch == OMAP_DSS_CHANNEL_DIGIT) REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); else /* OMAP_DSS_CHANNEL_LCD2 */ REG_FLD_MOD(DISPC_CONFIG2, enable, 18, 18); + enable_clocks(0); } bool dispc_alpha_blending_enabled(enum omap_channel ch) { @@ -2255,6 +2229,7 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch) if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) return false; + enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) enabled = REG_GET(DISPC_CONFIG, 18, 18); else if (ch == OMAP_DSS_CHANNEL_DIGIT) @@ -2263,6 +2238,7 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch) enabled = REG_GET(DISPC_CONFIG2, 18, 18); else BUG(); + enable_clocks(0); return enabled; } @@ -2272,6 +2248,7 @@ bool dispc_trans_key_enabled(enum omap_channel ch) { bool enabled; + enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) enabled = REG_GET(DISPC_CONFIG, 10, 10); else if (ch == OMAP_DSS_CHANNEL_DIGIT) @@ -2280,6 +2257,7 @@ bool dispc_trans_key_enabled(enum omap_channel ch) enabled = REG_GET(DISPC_CONFIG2, 10, 10); else BUG(); + enable_clocks(0); return enabled; } @@ -2307,10 +2285,12 @@ void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines) return; } + enable_clocks(1); if (channel == OMAP_DSS_CHANNEL_LCD2) REG_FLD_MOD(DISPC_CONTROL2, code, 9, 8); else REG_FLD_MOD(DISPC_CONTROL, code, 9, 8); + enable_clocks(0); } void dispc_set_parallel_interface_mode(enum omap_channel channel, @@ -2342,6 +2322,8 @@ void dispc_set_parallel_interface_mode(enum omap_channel channel, return; } + enable_clocks(1); + if (channel == OMAP_DSS_CHANNEL_LCD2) { l = dispc_read_reg(DISPC_CONTROL2); l = FLD_MOD(l, stallmode, 11, 11); @@ -2353,6 +2335,8 @@ void dispc_set_parallel_interface_mode(enum omap_channel channel, l = FLD_MOD(l, gpout1, 16, 16); dispc_write_reg(DISPC_CONTROL, l); } + + enable_clocks(0); } static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, @@ -2405,8 +2389,10 @@ static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw, FLD_VAL(vbp, 31, 20); } + enable_clocks(1); dispc_write_reg(DISPC_TIMING_H(channel), timing_h); dispc_write_reg(DISPC_TIMING_V(channel), timing_v); + enable_clocks(0); } /* change name to mode? */ @@ -2449,8 +2435,10 @@ static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div, BUG_ON(lck_div < 1); BUG_ON(pck_div < 2); + enable_clocks(1); dispc_write_reg(DISPC_DIVISORo(channel), FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); + enable_clocks(0); } static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div, @@ -2469,7 +2457,7 @@ unsigned long dispc_fclk_rate(void) switch (dss_get_dispc_clk_source()) { case OMAP_DSS_CLK_SRC_FCK: - r = clk_get_rate(dispc.dss_clk); + r = dss_clk_get_rate(DSS_CLK_FCK); break; case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: dsidev = dsi_get_dsidev_from_id(0); @@ -2499,7 +2487,7 @@ unsigned long dispc_lclk_rate(enum omap_channel channel) switch (dss_get_lcd_clk_source(channel)) { case OMAP_DSS_CLK_SRC_FCK: - r = clk_get_rate(dispc.dss_clk); + r = dss_clk_get_rate(DSS_CLK_FCK); break; case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: dsidev = dsi_get_dsidev_from_id(0); @@ -2538,8 +2526,7 @@ void dispc_dump_clocks(struct seq_file *s) enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(); enum omap_dss_clk_source lcd_clk_src; - if (dispc_runtime_get()) - return; + enable_clocks(1); seq_printf(s, "- DISPC -\n"); @@ -2587,8 +2574,7 @@ void dispc_dump_clocks(struct seq_file *s) seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd); } - - dispc_runtime_put(); + enable_clocks(0); } #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS @@ -2643,8 +2629,7 @@ void dispc_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r)) - if (dispc_runtime_get()) - return; + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); DUMPREG(DISPC_REVISION); DUMPREG(DISPC_SYSCONFIG); @@ -2664,8 +2649,7 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD)); - if (dss_has_feature(FEAT_GLOBAL_ALPHA)) - DUMPREG(DISPC_GLOBAL_ALPHA); + DUMPREG(DISPC_GLOBAL_ALPHA); DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); if (dss_has_feature(FEAT_MGR_LCD2)) { @@ -2696,25 +2680,20 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); - if (dss_has_feature(FEAT_CPR)) { - DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); - } + DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); + DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); + DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); if (dss_has_feature(FEAT_MGR_LCD2)) { DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); - if (dss_has_feature(FEAT_CPR)) { - DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); - } + DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); + DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); + DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); } - if (dss_has_feature(FEAT_PRELOAD)) - DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX)); + DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX)); DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO1)); DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO1)); @@ -2765,16 +2744,14 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2)); DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3)); DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4)); - if (dss_has_feature(FEAT_FIR_COEF_V)) { - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7)); - } + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 3)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 4)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7)); if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO1)); @@ -2835,17 +2812,14 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2)); DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3)); DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4)); - - if (dss_has_feature(FEAT_FIR_COEF_V)) { - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7)); - } + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 3)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 4)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7)); if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO2)); @@ -2884,12 +2858,10 @@ void dispc_dump_regs(struct seq_file *s) if (dss_has_feature(FEAT_ATTR2)) DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); - if (dss_has_feature(FEAT_PRELOAD)) { - DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2)); - } + DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1)); + DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2)); - dispc_runtime_put(); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); #undef DUMPREG } @@ -2910,7 +2882,9 @@ static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf, l |= FLD_VAL(acbi, 11, 8); l |= FLD_VAL(acb, 7, 0); + enable_clocks(1); dispc_write_reg(DISPC_POL_FREQ(channel), l); + enable_clocks(0); } void dispc_set_pol_freq(enum omap_channel channel, @@ -3031,11 +3005,15 @@ static void _omap_dispc_set_irqs(void) mask |= isr_data->mask; } + enable_clocks(1); + old_mask = dispc_read_reg(DISPC_IRQENABLE); /* clear the irqstatus for newly enabled irqs */ dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask); dispc_write_reg(DISPC_IRQENABLE, mask); + + enable_clocks(0); } int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) @@ -3544,6 +3522,13 @@ static void _omap_dispc_initial_config(void) { u32 l; + l = dispc_read_reg(DISPC_SYSCONFIG); + l = FLD_MOD(l, 2, 13, 12); /* MIDLEMODE: smart standby */ + l = FLD_MOD(l, 2, 4, 3); /* SIDLEMODE: smart idle */ + l = FLD_MOD(l, 1, 2, 2); /* ENWAKEUP */ + l = FLD_MOD(l, 1, 0, 0); /* AUTOIDLE */ + dispc_write_reg(DISPC_SYSCONFIG, l); + /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */ if (dss_has_feature(FEAT_CORE_CLK_DIV)) { l = dispc_read_reg(DISPC_DIVISOR); @@ -3569,25 +3554,67 @@ static void _omap_dispc_initial_config(void) dispc_read_plane_fifo_sizes(); } +int dispc_enable_plane(enum omap_plane plane, bool enable) +{ + DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); + + enable_clocks(1); + _dispc_enable_plane(plane, enable); + enable_clocks(0); + + return 0; +} + +int dispc_setup_plane(enum omap_plane plane, + u32 paddr, u16 screen_width, + u16 pos_x, u16 pos_y, + u16 width, u16 height, + u16 out_width, u16 out_height, + enum omap_color_mode color_mode, + bool ilace, + enum omap_dss_rotation_type rotation_type, + u8 rotation, bool mirror, u8 global_alpha, + u8 pre_mult_alpha, enum omap_channel channel, + u32 puv_addr) +{ + int r = 0; + + DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d, %d, %dx%d -> " + "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n", + plane, paddr, screen_width, pos_x, pos_y, + width, height, + out_width, out_height, + ilace, color_mode, + rotation, mirror, channel); + + enable_clocks(1); + + r = _dispc_setup_plane(plane, + paddr, screen_width, + pos_x, pos_y, + width, height, + out_width, out_height, + color_mode, ilace, + rotation_type, + rotation, mirror, + global_alpha, + pre_mult_alpha, + channel, puv_addr); + + enable_clocks(0); + + return r; +} + /* DISPC HW IP initialisation */ static int omap_dispchw_probe(struct platform_device *pdev) { u32 rev; int r = 0; struct resource *dispc_mem; - struct clk *clk; dispc.pdev = pdev; - clk = clk_get(&pdev->dev, "dss_clk"); - if (IS_ERR(clk)) { - DSSERR("can't get dss_clk\n"); - r = PTR_ERR(clk); - goto err_get_clk; - } - - dispc.dss_clk = clk; - spin_lock_init(&dispc.irq_lock); #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS @@ -3601,103 +3628,62 @@ static int omap_dispchw_probe(struct platform_device *pdev) if (!dispc_mem) { DSSERR("can't get IORESOURCE_MEM DISPC\n"); r = -EINVAL; - goto err_ioremap; + goto fail0; } dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem)); if (!dispc.base) { DSSERR("can't ioremap DISPC\n"); r = -ENOMEM; - goto err_ioremap; + goto fail0; } dispc.irq = platform_get_irq(dispc.pdev, 0); if (dispc.irq < 0) { DSSERR("platform_get_irq failed\n"); r = -ENODEV; - goto err_irq; + goto fail1; } r = request_irq(dispc.irq, omap_dispc_irq_handler, IRQF_SHARED, "OMAP DISPC", dispc.pdev); if (r < 0) { DSSERR("request_irq failed\n"); - goto err_irq; + goto fail1; } - pm_runtime_enable(&pdev->dev); - - r = dispc_runtime_get(); - if (r) - goto err_runtime_get; + enable_clocks(1); _omap_dispc_initial_config(); _omap_dispc_initialize_irq(); + dispc_save_context(); + rev = dispc_read_reg(DISPC_REVISION); dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - dispc_runtime_put(); + enable_clocks(0); return 0; - -err_runtime_get: - pm_runtime_disable(&pdev->dev); - free_irq(dispc.irq, dispc.pdev); -err_irq: +fail1: iounmap(dispc.base); -err_ioremap: - clk_put(dispc.dss_clk); -err_get_clk: +fail0: return r; } static int omap_dispchw_remove(struct platform_device *pdev) { - pm_runtime_disable(&pdev->dev); - - clk_put(dispc.dss_clk); - free_irq(dispc.irq, dispc.pdev); iounmap(dispc.base); return 0; } -static int dispc_runtime_suspend(struct device *dev) -{ - dispc_save_context(); - clk_disable(dispc.dss_clk); - dss_runtime_put(); - - return 0; -} - -static int dispc_runtime_resume(struct device *dev) -{ - int r; - - r = dss_runtime_get(); - if (r < 0) - return r; - - clk_enable(dispc.dss_clk); - dispc_restore_context(); - - return 0; -} - -static const struct dev_pm_ops dispc_pm_ops = { - .runtime_suspend = dispc_runtime_suspend, - .runtime_resume = dispc_runtime_resume, -}; - static struct platform_driver omap_dispchw_driver = { .probe = omap_dispchw_probe, .remove = omap_dispchw_remove, .driver = { .name = "omapdss_dispc", .owner = THIS_MODULE, - .pm = &dispc_pm_ops, }, }; diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index a0bbdf6684b..c2dfc8c5005 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -65,6 +65,48 @@ static ssize_t display_enabled_store(struct device *dev, return size; } +static ssize_t display_upd_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + enum omap_dss_update_mode mode = OMAP_DSS_UPDATE_AUTO; + if (dssdev->driver->get_update_mode) + mode = dssdev->driver->get_update_mode(dssdev); + return snprintf(buf, PAGE_SIZE, "%d\n", mode); +} + +static ssize_t display_upd_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + int val, r; + enum omap_dss_update_mode mode; + + if (!dssdev->driver->set_update_mode) + return -EINVAL; + + r = kstrtoint(buf, 0, &val); + if (r) + return r; + + switch (val) { + case OMAP_DSS_UPDATE_DISABLED: + case OMAP_DSS_UPDATE_AUTO: + case OMAP_DSS_UPDATE_MANUAL: + mode = (enum omap_dss_update_mode)val; + break; + default: + return -EINVAL; + } + + r = dssdev->driver->set_update_mode(dssdev, mode); + if (r) + return r; + + return size; +} + static ssize_t display_tear_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -252,6 +294,8 @@ static ssize_t display_wss_store(struct device *dev, static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR, display_enabled_show, display_enabled_store); +static DEVICE_ATTR(update_mode, S_IRUGO|S_IWUSR, + display_upd_mode_show, display_upd_mode_store); static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR, display_tear_show, display_tear_store); static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR, @@ -265,6 +309,7 @@ static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR, static struct device_attribute *display_sysfs_attrs[] = { &dev_attr_enabled, + &dev_attr_update_mode, &dev_attr_tear_elim, &dev_attr_timings, &dev_attr_rotate, diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index f053b180ecd..ff6bd30132d 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -23,6 +23,7 @@ #define DSS_SUBSYS_NAME "DPI" #include <linux/kernel.h> +#include <linux/clk.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/errno.h> @@ -129,6 +130,8 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) bool is_tft; int r = 0; + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); + dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config, dssdev->panel.acbi, dssdev->panel.acb); @@ -141,7 +144,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck, &lck_div, &pck_div); if (r) - return r; + goto err0; pck = fck / lck_div / pck_div / 1000; @@ -155,10 +158,12 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) dispc_set_lcd_timings(dssdev->manager->id, t); - return 0; +err0: + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + return r; } -static void dpi_basic_init(struct omap_dss_device *dssdev) +static int dpi_basic_init(struct omap_dss_device *dssdev) { bool is_tft; @@ -170,6 +175,8 @@ static void dpi_basic_init(struct omap_dss_device *dssdev) OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN); dispc_set_tft_data_lines(dssdev->manager->id, dssdev->phy.dpi.data_lines); + + return 0; } int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) @@ -179,38 +186,31 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); - goto err_start_dev; + goto err0; } if (cpu_is_omap34xx()) { r = regulator_enable(dpi.vdds_dsi_reg); if (r) - goto err_reg_enable; + goto err1; } - r = dss_runtime_get(); - if (r) - goto err_get_dss; + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); - r = dispc_runtime_get(); + r = dpi_basic_init(dssdev); if (r) - goto err_get_dispc; - - dpi_basic_init(dssdev); + goto err2; if (dpi_use_dsi_pll(dssdev)) { - r = dsi_runtime_get(dpi.dsidev); - if (r) - goto err_get_dsi; - + dss_clk_enable(DSS_CLK_SYSCK); r = dsi_pll_init(dpi.dsidev, 0, 1); if (r) - goto err_dsi_pll_init; + goto err3; } r = dpi_set_mode(dssdev); if (r) - goto err_set_mode; + goto err4; mdelay(2); @@ -218,22 +218,19 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) return 0; -err_set_mode: +err4: if (dpi_use_dsi_pll(dssdev)) dsi_pll_uninit(dpi.dsidev, true); -err_dsi_pll_init: +err3: if (dpi_use_dsi_pll(dssdev)) - dsi_runtime_put(dpi.dsidev); -err_get_dsi: - dispc_runtime_put(); -err_get_dispc: - dss_runtime_put(); -err_get_dss: + dss_clk_disable(DSS_CLK_SYSCK); +err2: + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); if (cpu_is_omap34xx()) regulator_disable(dpi.vdds_dsi_reg); -err_reg_enable: +err1: omap_dss_stop_device(dssdev); -err_start_dev: +err0: return r; } EXPORT_SYMBOL(omapdss_dpi_display_enable); @@ -245,11 +242,10 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) if (dpi_use_dsi_pll(dssdev)) { dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); dsi_pll_uninit(dpi.dsidev, true); - dsi_runtime_put(dpi.dsidev); + dss_clk_disable(DSS_CLK_SYSCK); } - dispc_runtime_put(); - dss_runtime_put(); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); if (cpu_is_omap34xx()) regulator_disable(dpi.vdds_dsi_reg); @@ -261,26 +257,11 @@ EXPORT_SYMBOL(omapdss_dpi_display_disable); void dpi_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - int r; - DSSDBG("dpi_set_timings\n"); dssdev->panel.timings = *timings; if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - r = dss_runtime_get(); - if (r) - return; - - r = dispc_runtime_get(); - if (r) { - dss_runtime_put(); - return; - } - dpi_set_mode(dssdev); dispc_go(dssdev->manager->id); - - dispc_runtime_put(); - dss_runtime_put(); } } EXPORT_SYMBOL(dpi_set_timings); diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index b6a57bb7a61..345757cfcbe 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -36,7 +36,6 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/debugfs.h> -#include <linux/pm_runtime.h> #include <video/omapdss.h> #include <plat/clock.h> @@ -268,12 +267,8 @@ struct dsi_isr_tables { struct dsi_data { struct platform_device *pdev; void __iomem *base; - int irq; - struct clk *dss_clk; - struct clk *sys_clk; - void (*dsi_mux_pads)(bool enable); struct dsi_clock_info current_cinfo; @@ -394,6 +389,15 @@ static inline u32 dsi_read_reg(struct platform_device *dsidev, return __raw_readl(dsi->base + idx.idx); } + +void dsi_save_context(void) +{ +} + +void dsi_restore_context(void) +{ +} + void dsi_bus_lock(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); @@ -489,18 +493,9 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name) total_bytes * 1000 / total_us); } #else -static inline void dsi_perf_mark_setup(struct platform_device *dsidev) -{ -} - -static inline void dsi_perf_mark_start(struct platform_device *dsidev) -{ -} - -static inline void dsi_perf_show(struct platform_device *dsidev, - const char *name) -{ -} +#define dsi_perf_mark_setup(x) +#define dsi_perf_mark_start(x) +#define dsi_perf_show(x, y) #endif static void print_irq_status(u32 status) @@ -1044,27 +1039,13 @@ static u32 dsi_get_errors(struct platform_device *dsidev) return e; } -int dsi_runtime_get(struct platform_device *dsidev) +/* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */ +static inline void enable_clocks(bool enable) { - int r; - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - - DSSDBG("dsi_runtime_get\n"); - - r = pm_runtime_get_sync(&dsi->pdev->dev); - WARN_ON(r < 0); - return r < 0 ? r : 0; -} - -void dsi_runtime_put(struct platform_device *dsidev) -{ - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - int r; - - DSSDBG("dsi_runtime_put\n"); - - r = pm_runtime_put(&dsi->pdev->dev); - WARN_ON(r < 0); + if (enable) + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); + else + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); } /* source clock for DSI PLL. this could also be PCLKFREE */ @@ -1074,9 +1055,9 @@ static inline void dsi_enable_pll_clock(struct platform_device *dsidev, struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); if (enable) - clk_enable(dsi->sys_clk); + dss_clk_enable(DSS_CLK_SYSCK); else - clk_disable(dsi->sys_clk); + dss_clk_disable(DSS_CLK_SYSCK); if (enable && dsi->pll_locked) { if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) @@ -1169,11 +1150,10 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev) { unsigned long r; int dsi_module = dsi_get_dsidev_id(dsidev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); if (dss_get_dsi_clk_source(dsi_module) == OMAP_DSS_CLK_SRC_FCK) { /* DSI FCLK source is DSS_CLK_FCK */ - r = clk_get_rate(dsi->dss_clk); + r = dss_clk_get_rate(DSS_CLK_FCK); } else { /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */ r = dsi_get_pll_hsdiv_dsi_rate(dsidev); @@ -1282,7 +1262,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, return -EINVAL; if (cinfo->use_sys_clk) { - cinfo->clkin = clk_get_rate(dsi->sys_clk); + cinfo->clkin = dss_clk_get_rate(DSS_CLK_SYSCK); /* XXX it is unclear if highfreq should be used * with DSS_SYS_CLK source also */ cinfo->highfreq = 0; @@ -1331,7 +1311,7 @@ int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft, int match = 0; unsigned long dss_sys_clk, max_dss_fck; - dss_sys_clk = clk_get_rate(dsi->sys_clk); + dss_sys_clk = dss_clk_get_rate(DSS_CLK_SYSCK); max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); @@ -1621,6 +1601,7 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, dsi->vdds_dsi_reg = vdds_dsi; } + enable_clocks(1); dsi_enable_pll_clock(dsidev, 1); /* * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4. @@ -1672,6 +1653,7 @@ err1: } err0: dsi_disable_scp_clk(dsidev); + enable_clocks(0); dsi_enable_pll_clock(dsidev, 0); return r; } @@ -1689,6 +1671,7 @@ void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes) } dsi_disable_scp_clk(dsidev); + enable_clocks(0); dsi_enable_pll_clock(dsidev, 0); DSSDBG("PLL uninit done\n"); @@ -1705,8 +1688,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, dispc_clk_src = dss_get_dispc_clk_source(); dsi_clk_src = dss_get_dsi_clk_source(dsi_module); - if (dsi_runtime_get(dsidev)) - return; + enable_clocks(1); seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1); @@ -1749,7 +1731,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, seq_printf(s, "LP_CLK\t\t%lu\n", cinfo->lp_clk); - dsi_runtime_put(dsidev); + enable_clocks(0); } void dsi_dump_clocks(struct seq_file *s) @@ -1891,8 +1873,7 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev, { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsidev, r)) - if (dsi_runtime_get(dsidev)) - return; + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); dsi_enable_scp_clk(dsidev); DUMPREG(DSI_REVISION); @@ -1966,7 +1947,7 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev, DUMPREG(DSI_PLL_CONFIGURATION2); dsi_disable_scp_clk(dsidev); - dsi_runtime_put(dsidev); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); #undef DUMPREG } @@ -2482,6 +2463,28 @@ static void dsi_cio_uninit(struct platform_device *dsidev) dsi->dsi_mux_pads(false); } +static int _dsi_wait_reset(struct platform_device *dsidev) +{ + int t = 0; + + while (REG_GET(dsidev, DSI_SYSSTATUS, 0, 0) == 0) { + if (++t > 5) { + DSSERR("soft reset failed\n"); + return -ENODEV; + } + udelay(1); + } + + return 0; +} + +static int _dsi_reset(struct platform_device *dsidev) +{ + /* Soft reset */ + REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 1, 1); + return _dsi_wait_reset(dsidev); +} + static void dsi_config_tx_fifo(struct platform_device *dsidev, enum fifo_size size1, enum fifo_size size2, enum fifo_size size3, enum fifo_size size4) @@ -3383,10 +3386,6 @@ static int dsi_enter_ulps(struct platform_device *dsidev) dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion, DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); - /* Reset LANEx_ULPS_SIG2 */ - REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (0 << 0) | (0 << 1) | (0 << 2), - 7, 5); - dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS); dsi_if_enable(dsidev, false); @@ -4199,6 +4198,22 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, dsi_pll_uninit(dsidev, disconnect_lanes); } +static int dsi_core_init(struct platform_device *dsidev) +{ + /* Autoidle */ + REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 0, 0); + + /* ENWAKEUP */ + REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 2, 2); + + /* SIDLEMODE smart-idle */ + REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 2, 4, 3); + + _dsi_initialize_irq(dsidev); + + return 0; +} + int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); @@ -4214,37 +4229,37 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); - goto err_start_dev; + goto err0; } - r = dsi_runtime_get(dsidev); - if (r) - goto err_get_dsi; - + enable_clocks(1); dsi_enable_pll_clock(dsidev, 1); - _dsi_initialize_irq(dsidev); + r = _dsi_reset(dsidev); + if (r) + goto err1; + + dsi_core_init(dsidev); r = dsi_display_init_dispc(dssdev); if (r) - goto err_init_dispc; + goto err1; r = dsi_display_init_dsi(dssdev); if (r) - goto err_init_dsi; + goto err2; mutex_unlock(&dsi->lock); return 0; -err_init_dsi: +err2: dsi_display_uninit_dispc(dssdev); -err_init_dispc: +err1: + enable_clocks(0); dsi_enable_pll_clock(dsidev, 0); - dsi_runtime_put(dsidev); -err_get_dsi: omap_dss_stop_device(dssdev); -err_start_dev: +err0: mutex_unlock(&dsi->lock); DSSDBG("dsi_display_enable FAILED\n"); return r; @@ -4267,7 +4282,7 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev, dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps); - dsi_runtime_put(dsidev); + enable_clocks(0); dsi_enable_pll_clock(dsidev, 0); omap_dss_stop_device(dssdev); @@ -4422,44 +4437,7 @@ static void dsi_calc_clock_param_ranges(struct platform_device *dsidev) dsi->lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV); } -static int dsi_get_clocks(struct platform_device *dsidev) -{ - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct clk *clk; - - clk = clk_get(&dsidev->dev, "dss_clk"); - if (IS_ERR(clk)) { - DSSERR("can't get dss_clk\n"); - return PTR_ERR(clk); - } - - dsi->dss_clk = clk; - - clk = clk_get(&dsidev->dev, "sys_clk"); - if (IS_ERR(clk)) { - DSSERR("can't get sys_clk\n"); - clk_put(dsi->dss_clk); - dsi->dss_clk = NULL; - return PTR_ERR(clk); - } - - dsi->sys_clk = clk; - - return 0; -} - -static void dsi_put_clocks(struct platform_device *dsidev) -{ - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - - if (dsi->dss_clk) - clk_put(dsi->dss_clk); - if (dsi->sys_clk) - clk_put(dsi->sys_clk); -} - -/* DSI1 HW IP initialisation */ -static int omap_dsi1hw_probe(struct platform_device *dsidev) +static int dsi_init(struct platform_device *dsidev) { struct omap_display_platform_data *dss_plat_data; struct omap_dss_board_info *board_info; @@ -4471,7 +4449,7 @@ static int omap_dsi1hw_probe(struct platform_device *dsidev) dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); if (!dsi) { r = -ENOMEM; - goto err_alloc; + goto err0; } dsi->pdev = dsidev; @@ -4494,12 +4472,6 @@ static int omap_dsi1hw_probe(struct platform_device *dsidev) mutex_init(&dsi->lock); sema_init(&dsi->bus_lock, 1); - r = dsi_get_clocks(dsidev); - if (r) - goto err_get_clk; - - pm_runtime_enable(&dsidev->dev); - INIT_DELAYED_WORK_DEFERRABLE(&dsi->framedone_timeout_work, dsi_framedone_timeout_work_callback); @@ -4512,26 +4484,26 @@ static int omap_dsi1hw_probe(struct platform_device *dsidev) if (!dsi_mem) { DSSERR("can't get IORESOURCE_MEM DSI\n"); r = -EINVAL; - goto err_ioremap; + goto err1; } dsi->base = ioremap(dsi_mem->start, resource_size(dsi_mem)); if (!dsi->base) { DSSERR("can't ioremap DSI\n"); r = -ENOMEM; - goto err_ioremap; + goto err1; } dsi->irq = platform_get_irq(dsi->pdev, 0); if (dsi->irq < 0) { DSSERR("platform_get_irq failed\n"); r = -ENODEV; - goto err_get_irq; + goto err2; } r = request_irq(dsi->irq, omap_dsi_irq_handler, IRQF_SHARED, dev_name(&dsidev->dev), dsi->pdev); if (r < 0) { DSSERR("request_irq failed\n"); - goto err_get_irq; + goto err2; } /* DSI VCs initialization */ @@ -4543,9 +4515,7 @@ static int omap_dsi1hw_probe(struct platform_device *dsidev) dsi_calc_clock_param_ranges(dsidev); - r = dsi_runtime_get(dsidev); - if (r) - goto err_get_dsi; + enable_clocks(1); rev = dsi_read_reg(dsidev, DSI_REVISION); dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", @@ -4553,32 +4523,21 @@ static int omap_dsi1hw_probe(struct platform_device *dsidev) dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev); - dsi_runtime_put(dsidev); + enable_clocks(0); return 0; - -err_get_dsi: - free_irq(dsi->irq, dsi->pdev); -err_get_irq: +err2: iounmap(dsi->base); -err_ioremap: - pm_runtime_disable(&dsidev->dev); -err_get_clk: +err1: kfree(dsi); -err_alloc: +err0: return r; } -static int omap_dsi1hw_remove(struct platform_device *dsidev) +static void dsi_exit(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - WARN_ON(dsi->scp_clk_refcount > 0); - - pm_runtime_disable(&dsidev->dev); - - dsi_put_clocks(dsidev); - if (dsi->vdds_dsi_reg != NULL) { if (dsi->vdds_dsi_enabled) { regulator_disable(dsi->vdds_dsi_reg); @@ -4594,56 +4553,38 @@ static int omap_dsi1hw_remove(struct platform_device *dsidev) kfree(dsi); - return 0; + DSSDBG("omap_dsi_exit\n"); } -static int dsi_runtime_suspend(struct device *dev) +/* DSI1 HW IP initialisation */ +static int omap_dsi1hw_probe(struct platform_device *dsidev) { - struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev)); - - clk_disable(dsi->dss_clk); - - dispc_runtime_put(); - dss_runtime_put(); + int r; - return 0; + r = dsi_init(dsidev); + if (r) { + DSSERR("Failed to initialize DSI\n"); + goto err_dsi; + } +err_dsi: + return r; } -static int dsi_runtime_resume(struct device *dev) +static int omap_dsi1hw_remove(struct platform_device *dsidev) { - struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev)); - int r; - - r = dss_runtime_get(); - if (r) - goto err_get_dss; - - r = dispc_runtime_get(); - if (r) - goto err_get_dispc; - - clk_enable(dsi->dss_clk); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + dsi_exit(dsidev); + WARN_ON(dsi->scp_clk_refcount > 0); return 0; - -err_get_dispc: - dss_runtime_put(); -err_get_dss: - return r; } -static const struct dev_pm_ops dsi_pm_ops = { - .runtime_suspend = dsi_runtime_suspend, - .runtime_resume = dsi_runtime_resume, -}; - static struct platform_driver omap_dsi1hw_driver = { .probe = omap_dsi1hw_probe, .remove = omap_dsi1hw_remove, .driver = { .name = "omapdss_dsi1", .owner = THIS_MODULE, - .pm = &dsi_pm_ops, }, }; diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 5c6499a4d6a..d9489d5c4f0 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -28,8 +28,6 @@ #include <linux/delay.h> #include <linux/seq_file.h> #include <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> #include <video/omapdss.h> #include <plat/clock.h> @@ -61,9 +59,15 @@ struct dss_reg { static struct { struct platform_device *pdev; void __iomem *base; + int ctx_id; struct clk *dpll4_m4_ck; - struct clk *dss_clk; + struct clk *dss_ick; + struct clk *dss_fck; + struct clk *dss_sys_clk; + struct clk *dss_tv_fck; + struct clk *dss_video_fck; + unsigned num_clks_enabled; unsigned long cache_req_pck; unsigned long cache_prate; @@ -74,7 +78,6 @@ static struct { enum omap_dss_clk_source dispc_clk_source; enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS]; - bool ctx_valid; u32 ctx[DSS_SZ_REGS / sizeof(u32)]; } dss; @@ -84,6 +87,13 @@ static const char * const dss_generic_clk_source_names[] = { [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK", }; +static void dss_clk_enable_all_no_ctx(void); +static void dss_clk_disable_all_no_ctx(void); +static void dss_clk_enable_no_ctx(enum dss_clock clks); +static void dss_clk_disable_no_ctx(enum dss_clock clks); + +static int _omap_dss_wait_reset(void); + static inline void dss_write_reg(const struct dss_reg idx, u32 val) { __raw_writel(val, dss.base + idx.idx); @@ -99,10 +109,12 @@ static inline u32 dss_read_reg(const struct dss_reg idx) #define RR(reg) \ dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)]) -static void dss_save_context(void) +void dss_save_context(void) { - DSSDBG("dss_save_context\n"); + if (cpu_is_omap24xx()) + return; + SR(SYSCONFIG); SR(CONTROL); if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & @@ -110,19 +122,14 @@ static void dss_save_context(void) SR(SDI_CONTROL); SR(PLL_CONTROL); } - - dss.ctx_valid = true; - - DSSDBG("context saved\n"); } -static void dss_restore_context(void) +void dss_restore_context(void) { - DSSDBG("dss_restore_context\n"); - - if (!dss.ctx_valid) - return; + if (_omap_dss_wait_reset()) + DSSERR("DSS not coming out of reset after sleep\n"); + RR(SYSCONFIG); RR(CONTROL); if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & @@ -130,8 +137,6 @@ static void dss_restore_context(void) RR(SDI_CONTROL); RR(PLL_CONTROL); } - - DSSDBG("context restored\n"); } #undef SR @@ -229,7 +234,6 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src) return dss_generic_clk_source_names[clk_src]; } - void dss_dump_clocks(struct seq_file *s) { unsigned long dpll4_ck_rate; @@ -237,14 +241,13 @@ void dss_dump_clocks(struct seq_file *s) const char *fclk_name, *fclk_real_name; unsigned long fclk_rate; - if (dss_runtime_get()) - return; + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); seq_printf(s, "- DSS -\n"); fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK); fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK); - fclk_rate = clk_get_rate(dss.dss_clk); + fclk_rate = dss_clk_get_rate(DSS_CLK_FCK); if (dss.dpll4_m4_ck) { dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); @@ -270,15 +273,14 @@ void dss_dump_clocks(struct seq_file *s) fclk_rate); } - dss_runtime_put(); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); } void dss_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r)) - if (dss_runtime_get()) - return; + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); DUMPREG(DSS_REVISION); DUMPREG(DSS_SYSCONFIG); @@ -292,7 +294,7 @@ void dss_dump_regs(struct seq_file *s) DUMPREG(DSS_SDI_STATUS); } - dss_runtime_put(); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); #undef DUMPREG } @@ -435,7 +437,7 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo) } else { if (cinfo->fck_div != 0) return -EINVAL; - cinfo->fck = clk_get_rate(dss.dss_clk); + cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK); } return 0; @@ -465,7 +467,7 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) int dss_get_clock_div(struct dss_clock_info *cinfo) { - cinfo->fck = clk_get_rate(dss.dss_clk); + cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK); if (dss.dpll4_m4_ck) { unsigned long prate; @@ -510,7 +512,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); - fck = clk_get_rate(dss.dss_clk); + fck = dss_clk_get_rate(DSS_CLK_FCK); if (req_pck == dss.cache_req_pck && ((cpu_is_omap34xx() && prate == dss.cache_prate) || dss.cache_dss_cinfo.fck == fck)) { @@ -537,7 +539,7 @@ retry: if (dss.dpll4_m4_ck == NULL) { struct dispc_clock_info cur_dispc; /* XXX can we change the clock on omap2? */ - fck = clk_get_rate(dss.dss_clk); + fck = dss_clk_get_rate(DSS_CLK_FCK); fck_div = 1; dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc); @@ -614,6 +616,28 @@ found: return 0; } +static int _omap_dss_wait_reset(void) +{ + int t = 0; + + while (REG_GET(DSS_SYSSTATUS, 0, 0) == 0) { + if (++t > 1000) { + DSSERR("soft reset failed\n"); + return -ENODEV; + } + udelay(1); + } + + return 0; +} + +static int _omap_dss_reset(void) +{ + /* Soft reset */ + REG_FLD_MOD(DSS_SYSCONFIG, 1, 1, 1); + return _omap_dss_wait_reset(); +} + void dss_set_venc_output(enum omap_dss_venc_type type) { int l = 0; @@ -639,83 +663,424 @@ void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi) REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */ } -static int dss_get_clocks(void) +static int dss_init(void) { - struct clk *clk; int r; + u32 rev; + struct resource *dss_mem; + struct clk *dpll4_m4_ck; - clk = clk_get(&dss.pdev->dev, "dss_clk"); - if (IS_ERR(clk)) { - DSSERR("can't get clock dss_clk\n"); - r = PTR_ERR(clk); - goto err; + dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); + if (!dss_mem) { + DSSERR("can't get IORESOURCE_MEM DSS\n"); + r = -EINVAL; + goto fail0; + } + dss.base = ioremap(dss_mem->start, resource_size(dss_mem)); + if (!dss.base) { + DSSERR("can't ioremap DSS\n"); + r = -ENOMEM; + goto fail0; } - dss.dss_clk = clk; + /* disable LCD and DIGIT output. This seems to fix the synclost + * problem that we get, if the bootloader starts the DSS and + * the kernel resets it */ + omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440); + +#ifdef CONFIG_OMAP2_DSS_SLEEP_BEFORE_RESET + /* We need to wait here a bit, otherwise we sometimes start to + * get synclost errors, and after that only power cycle will + * restore DSS functionality. I have no idea why this happens. + * And we have to wait _before_ resetting the DSS, but after + * enabling clocks. + * + * This bug was at least present on OMAP3430. It's unknown + * if it happens on OMAP2 or OMAP3630. + */ + msleep(50); +#endif + _omap_dss_reset(); + + /* autoidle */ + REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0); + + /* Select DPLL */ + REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); + +#ifdef CONFIG_OMAP2_DSS_VENC + REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ + REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ + REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ +#endif if (cpu_is_omap34xx()) { - clk = clk_get(NULL, "dpll4_m4_ck"); - if (IS_ERR(clk)) { + dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck"); + if (IS_ERR(dpll4_m4_ck)) { DSSERR("Failed to get dpll4_m4_ck\n"); - r = PTR_ERR(clk); - goto err; + r = PTR_ERR(dpll4_m4_ck); + goto fail1; } } else if (cpu_is_omap44xx()) { - clk = clk_get(NULL, "dpll_per_m5x2_ck"); - if (IS_ERR(clk)) { - DSSERR("Failed to get dpll_per_m5x2_ck\n"); - r = PTR_ERR(clk); - goto err; + dpll4_m4_ck = clk_get(NULL, "dpll_per_m5x2_ck"); + if (IS_ERR(dpll4_m4_ck)) { + DSSERR("Failed to get dpll4_m4_ck\n"); + r = PTR_ERR(dpll4_m4_ck); + goto fail1; } } else { /* omap24xx */ - clk = NULL; + dpll4_m4_ck = NULL; } - dss.dpll4_m4_ck = clk; + dss.dpll4_m4_ck = dpll4_m4_ck; - return 0; + dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; + dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; + dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK; + dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; + dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; -err: - if (dss.dss_clk) - clk_put(dss.dss_clk); - if (dss.dpll4_m4_ck) - clk_put(dss.dpll4_m4_ck); + dss_save_context(); + + rev = dss_read_reg(DSS_REVISION); + printk(KERN_INFO "OMAP DSS rev %d.%d\n", + FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); + + return 0; +fail1: + iounmap(dss.base); +fail0: return r; } -static void dss_put_clocks(void) +static void dss_exit(void) { if (dss.dpll4_m4_ck) clk_put(dss.dpll4_m4_ck); - clk_put(dss.dss_clk); + + iounmap(dss.base); } -int dss_runtime_get(void) +/* CONTEXT */ +static int dss_get_ctx_id(void) { + struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data; int r; - DSSDBG("dss_runtime_get\n"); + if (!pdata->board_data->get_last_off_on_transaction_id) + return 0; + r = pdata->board_data->get_last_off_on_transaction_id(&dss.pdev->dev); + if (r < 0) { + dev_err(&dss.pdev->dev, "getting transaction ID failed, " + "will force context restore\n"); + r = -1; + } + return r; +} + +int dss_need_ctx_restore(void) +{ + int id = dss_get_ctx_id(); + + if (id < 0 || id != dss.ctx_id) { + DSSDBG("ctx id %d -> id %d\n", + dss.ctx_id, id); + dss.ctx_id = id; + return 1; + } else { + return 0; + } +} + +static void save_all_ctx(void) +{ + DSSDBG("save context\n"); + + dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK); + + dss_save_context(); + dispc_save_context(); +#ifdef CONFIG_OMAP2_DSS_DSI + dsi_save_context(); +#endif + + dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK); +} + +static void restore_all_ctx(void) +{ + DSSDBG("restore context\n"); + + dss_clk_enable_all_no_ctx(); - r = pm_runtime_get_sync(&dss.pdev->dev); - WARN_ON(r < 0); - return r < 0 ? r : 0; + dss_restore_context(); + dispc_restore_context(); +#ifdef CONFIG_OMAP2_DSS_DSI + dsi_restore_context(); +#endif + + dss_clk_disable_all_no_ctx(); } -void dss_runtime_put(void) +static int dss_get_clock(struct clk **clock, const char *clk_name) +{ + struct clk *clk; + + clk = clk_get(&dss.pdev->dev, clk_name); + + if (IS_ERR(clk)) { + DSSERR("can't get clock %s", clk_name); + return PTR_ERR(clk); + } + + *clock = clk; + + DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk)); + + return 0; +} + +static int dss_get_clocks(void) { int r; + struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data; + + dss.dss_ick = NULL; + dss.dss_fck = NULL; + dss.dss_sys_clk = NULL; + dss.dss_tv_fck = NULL; + dss.dss_video_fck = NULL; + + r = dss_get_clock(&dss.dss_ick, "ick"); + if (r) + goto err; + + r = dss_get_clock(&dss.dss_fck, "fck"); + if (r) + goto err; + + if (!pdata->opt_clock_available) { + r = -ENODEV; + goto err; + } + + if (pdata->opt_clock_available("sys_clk")) { + r = dss_get_clock(&dss.dss_sys_clk, "sys_clk"); + if (r) + goto err; + } + + if (pdata->opt_clock_available("tv_clk")) { + r = dss_get_clock(&dss.dss_tv_fck, "tv_clk"); + if (r) + goto err; + } + + if (pdata->opt_clock_available("video_clk")) { + r = dss_get_clock(&dss.dss_video_fck, "video_clk"); + if (r) + goto err; + } + + return 0; + +err: + if (dss.dss_ick) + clk_put(dss.dss_ick); + if (dss.dss_fck) + clk_put(dss.dss_fck); + if (dss.dss_sys_clk) + clk_put(dss.dss_sys_clk); + if (dss.dss_tv_fck) + clk_put(dss.dss_tv_fck); + if (dss.dss_video_fck) + clk_put(dss.dss_video_fck); - DSSDBG("dss_runtime_put\n"); + return r; +} - r = pm_runtime_put(&dss.pdev->dev); - WARN_ON(r < 0); +static void dss_put_clocks(void) +{ + if (dss.dss_video_fck) + clk_put(dss.dss_video_fck); + if (dss.dss_tv_fck) + clk_put(dss.dss_tv_fck); + if (dss.dss_sys_clk) + clk_put(dss.dss_sys_clk); + clk_put(dss.dss_fck); + clk_put(dss.dss_ick); +} + +unsigned long dss_clk_get_rate(enum dss_clock clk) +{ + switch (clk) { + case DSS_CLK_ICK: + return clk_get_rate(dss.dss_ick); + case DSS_CLK_FCK: + return clk_get_rate(dss.dss_fck); + case DSS_CLK_SYSCK: + return clk_get_rate(dss.dss_sys_clk); + case DSS_CLK_TVFCK: + return clk_get_rate(dss.dss_tv_fck); + case DSS_CLK_VIDFCK: + return clk_get_rate(dss.dss_video_fck); + } + + BUG(); + return 0; } +static unsigned count_clk_bits(enum dss_clock clks) +{ + unsigned num_clks = 0; + + if (clks & DSS_CLK_ICK) + ++num_clks; + if (clks & DSS_CLK_FCK) + ++num_clks; + if (clks & DSS_CLK_SYSCK) + ++num_clks; + if (clks & DSS_CLK_TVFCK) + ++num_clks; + if (clks & DSS_CLK_VIDFCK) + ++num_clks; + + return num_clks; +} + +static void dss_clk_enable_no_ctx(enum dss_clock clks) +{ + unsigned num_clks = count_clk_bits(clks); + + if (clks & DSS_CLK_ICK) + clk_enable(dss.dss_ick); + if (clks & DSS_CLK_FCK) + clk_enable(dss.dss_fck); + if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk) + clk_enable(dss.dss_sys_clk); + if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck) + clk_enable(dss.dss_tv_fck); + if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck) + clk_enable(dss.dss_video_fck); + + dss.num_clks_enabled += num_clks; +} + +void dss_clk_enable(enum dss_clock clks) +{ + bool check_ctx = dss.num_clks_enabled == 0; + + dss_clk_enable_no_ctx(clks); + + /* + * HACK: On omap4 the registers may not be accessible right after + * enabling the clocks. At some point this will be handled by + * pm_runtime, but for the time begin this should make things work. + */ + if (cpu_is_omap44xx() && check_ctx) + udelay(10); + + if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore()) + restore_all_ctx(); +} + +static void dss_clk_disable_no_ctx(enum dss_clock clks) +{ + unsigned num_clks = count_clk_bits(clks); + + if (clks & DSS_CLK_ICK) + clk_disable(dss.dss_ick); + if (clks & DSS_CLK_FCK) + clk_disable(dss.dss_fck); + if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk) + clk_disable(dss.dss_sys_clk); + if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck) + clk_disable(dss.dss_tv_fck); + if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck) + clk_disable(dss.dss_video_fck); + + dss.num_clks_enabled -= num_clks; +} + +void dss_clk_disable(enum dss_clock clks) +{ + if (cpu_is_omap34xx()) { + unsigned num_clks = count_clk_bits(clks); + + BUG_ON(dss.num_clks_enabled < num_clks); + + if (dss.num_clks_enabled == num_clks) + save_all_ctx(); + } + + dss_clk_disable_no_ctx(clks); +} + +static void dss_clk_enable_all_no_ctx(void) +{ + enum dss_clock clks; + + clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK; + if (cpu_is_omap34xx()) + clks |= DSS_CLK_VIDFCK; + dss_clk_enable_no_ctx(clks); +} + +static void dss_clk_disable_all_no_ctx(void) +{ + enum dss_clock clks; + + clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK; + if (cpu_is_omap34xx()) + clks |= DSS_CLK_VIDFCK; + dss_clk_disable_no_ctx(clks); +} + +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) +/* CLOCKS */ +static void core_dump_clocks(struct seq_file *s) +{ + int i; + struct clk *clocks[5] = { + dss.dss_ick, + dss.dss_fck, + dss.dss_sys_clk, + dss.dss_tv_fck, + dss.dss_video_fck + }; + + const char *names[5] = { + "ick", + "fck", + "sys_clk", + "tv_fck", + "video_fck" + }; + + seq_printf(s, "- CORE -\n"); + + seq_printf(s, "internal clk count\t\t%u\n", dss.num_clks_enabled); + + for (i = 0; i < 5; i++) { + if (!clocks[i]) + continue; + seq_printf(s, "%s (%s)%*s\t%lu\t%d\n", + names[i], + clocks[i]->name, + 24 - strlen(names[i]) - strlen(clocks[i]->name), + "", + clk_get_rate(clocks[i]), + clocks[i]->usecount); + } +} +#endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */ + /* DEBUGFS */ #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) void dss_debug_dump_clocks(struct seq_file *s) { + core_dump_clocks(s); dss_dump_clocks(s); dispc_dump_clocks(s); #ifdef CONFIG_OMAP2_DSS_DSI @@ -724,51 +1089,28 @@ void dss_debug_dump_clocks(struct seq_file *s) } #endif + /* DSS HW IP initialisation */ static int omap_dsshw_probe(struct platform_device *pdev) { - struct resource *dss_mem; - u32 rev; int r; dss.pdev = pdev; - dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); - if (!dss_mem) { - DSSERR("can't get IORESOURCE_MEM DSS\n"); - r = -EINVAL; - goto err_ioremap; - } - dss.base = ioremap(dss_mem->start, resource_size(dss_mem)); - if (!dss.base) { - DSSERR("can't ioremap DSS\n"); - r = -ENOMEM; - goto err_ioremap; - } - r = dss_get_clocks(); if (r) goto err_clocks; - pm_runtime_enable(&pdev->dev); - - r = dss_runtime_get(); - if (r) - goto err_runtime_get; + dss_clk_enable_all_no_ctx(); - /* Select DPLL */ - REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); + dss.ctx_id = dss_get_ctx_id(); + DSSDBG("initial ctx id %u\n", dss.ctx_id); -#ifdef CONFIG_OMAP2_DSS_VENC - REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ - REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ - REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ -#endif - dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; - dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; - dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK; - dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; - dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; + r = dss_init(); + if (r) { + DSSERR("Failed to initialize DSS\n"); + goto err_dss; + } r = dpi_init(); if (r) { @@ -782,66 +1124,42 @@ static int omap_dsshw_probe(struct platform_device *pdev) goto err_sdi; } - rev = dss_read_reg(DSS_REVISION); - printk(KERN_INFO "OMAP DSS rev %d.%d\n", - FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - - dss_runtime_put(); - + dss_clk_disable_all_no_ctx(); return 0; err_sdi: dpi_exit(); err_dpi: - dss_runtime_put(); -err_runtime_get: - pm_runtime_disable(&pdev->dev); + dss_exit(); +err_dss: + dss_clk_disable_all_no_ctx(); dss_put_clocks(); err_clocks: - iounmap(dss.base); -err_ioremap: return r; } static int omap_dsshw_remove(struct platform_device *pdev) { - dpi_exit(); - sdi_exit(); - iounmap(dss.base); + dss_exit(); - pm_runtime_disable(&pdev->dev); + /* + * As part of hwmod changes, DSS is not the only controller of dss + * clocks; hwmod framework itself will also enable clocks during hwmod + * init for dss, and autoidle is set in h/w for DSS. Hence, there's no + * need to disable clocks if their usecounts > 1. + */ + WARN_ON(dss.num_clks_enabled > 0); dss_put_clocks(); - - return 0; -} - -static int dss_runtime_suspend(struct device *dev) -{ - dss_save_context(); - clk_disable(dss.dss_clk); return 0; } -static int dss_runtime_resume(struct device *dev) -{ - clk_enable(dss.dss_clk); - dss_restore_context(); - return 0; -} - -static const struct dev_pm_ops dss_pm_ops = { - .runtime_suspend = dss_runtime_suspend, - .runtime_resume = dss_runtime_resume, -}; - static struct platform_driver omap_dsshw_driver = { .probe = omap_dsshw_probe, .remove = omap_dsshw_remove, .driver = { .name = "omapdss_dss", .owner = THIS_MODULE, - .pm = &dss_pm_ops, }, }; diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index ce17a613a30..8ab6d43329b 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -109,6 +109,14 @@ enum omap_parallel_interface_mode { OMAP_DSS_PARALLELMODE_DSI, }; +enum dss_clock { + DSS_CLK_ICK = 1 << 0, /* DSS_L3_ICLK and DSS_L4_ICLK */ + DSS_CLK_FCK = 1 << 1, /* DSS1_ALWON_FCLK */ + DSS_CLK_SYSCK = 1 << 2, /* DSS2_ALWON_FCLK */ + DSS_CLK_TVFCK = 1 << 3, /* DSS_TV_FCLK */ + DSS_CLK_VIDFCK = 1 << 4, /* DSS_96M_FCLK*/ +}; + enum dss_hdmi_venc_clk_source_select { DSS_VENC_TV_CLK = 0, DSS_HDMI_M_PCLK = 1, @@ -212,10 +220,13 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); int dss_init_platform_driver(void); void dss_uninit_platform_driver(void); -int dss_runtime_get(void); -void dss_runtime_put(void); - void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); +void dss_save_context(void); +void dss_restore_context(void); +void dss_clk_enable(enum dss_clock clks); +void dss_clk_disable(enum dss_clock clks); +unsigned long dss_clk_get_rate(enum dss_clock clk); +int dss_need_ctx_restore(void); const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); void dss_dump_clocks(struct seq_file *s); @@ -272,15 +283,15 @@ struct file_operations; int dsi_init_platform_driver(void); void dsi_uninit_platform_driver(void); -int dsi_runtime_get(struct platform_device *dsidev); -void dsi_runtime_put(struct platform_device *dsidev); - void dsi_dump_clocks(struct seq_file *s); void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir, const struct file_operations *debug_fops); void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir, const struct file_operations *debug_fops); +void dsi_save_context(void); +void dsi_restore_context(void); + int dsi_init_display(struct omap_dss_device *display); void dsi_irq_handler(void); unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev); @@ -306,13 +317,6 @@ static inline int dsi_init_platform_driver(void) static inline void dsi_uninit_platform_driver(void) { } -static inline int dsi_runtime_get(struct platform_device *dsidev) -{ - return 0; -} -static inline void dsi_runtime_put(struct platform_device *dsidev) -{ -} static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev) { WARN("%s: DSI not compiled in, returning rate as 0\n", __func__); @@ -380,8 +384,8 @@ void dispc_dump_regs(struct seq_file *s); void dispc_irq_handler(void); void dispc_fake_vsync_irq(void); -int dispc_runtime_get(void); -void dispc_runtime_put(void); +void dispc_save_context(void); +void dispc_restore_context(void); void dispc_enable_sidle(void); void dispc_disable_sidle(void); diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index bd420f9650c..1c18888e5df 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -286,9 +286,7 @@ static const struct omap_dss_features omap3430_dss_features = { FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | FEAT_FUNCGATED | FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF | - FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC | - FEAT_VENC_REQUIRES_TV_DAC_CLK | FEAT_CPR | FEAT_PRELOAD | - FEAT_FIR_COEF_V, + FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC, .num_mgrs = 2, .num_ovls = 3, @@ -308,8 +306,7 @@ static const struct omap_dss_features omap3630_dss_features = { FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED | FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG | - FEAT_DSI_PLL_FREQSEL | FEAT_CPR | FEAT_PRELOAD | - FEAT_FIR_COEF_V, + FEAT_DSI_PLL_FREQSEL, .num_mgrs = 2, .num_ovls = 3, @@ -330,8 +327,7 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = { FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 | FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC | FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH | - FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 | - FEAT_CPR | FEAT_PRELOAD | FEAT_FIR_COEF_V, + FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2, .num_mgrs = 3, .num_ovls = 3, @@ -352,8 +348,7 @@ static const struct omap_dss_features omap4_dss_features = { FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC | FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH | FEAT_DSI_GNQ | FEAT_HDMI_CTS_SWMODE | - FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 | FEAT_CPR | - FEAT_PRELOAD | FEAT_FIR_COEF_V, + FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2, .num_mgrs = 3, .num_ovls = 3, diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 5be8103a159..07b346f7d91 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -51,10 +51,6 @@ enum dss_feat_id { FEAT_HDMI_CTS_SWMODE = 1 << 19, FEAT_HANDLE_UV_SEPARATE = 1 << 20, FEAT_ATTR2 = 1 << 21, - FEAT_VENC_REQUIRES_TV_DAC_CLK = 1 << 22, - FEAT_CPR = 1 << 23, - FEAT_PRELOAD = 1 << 24, - FEAT_FIR_COEF_V = 1 << 25, }; /* DSS register field id */ diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 1bbf31329c7..b0555f4f0a7 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -29,9 +29,6 @@ #include <linux/mutex.h> #include <linux/delay.h> #include <linux/string.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> -#include <linux/clk.h> #include <video/omapdss.h> #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) @@ -54,9 +51,6 @@ static struct { u8 edid_set; bool custom_set; struct hdmi_config cfg; - - struct clk *sys_clk; - struct clk *hdmi_clk; } hdmi; /* @@ -168,27 +162,6 @@ static inline int hdmi_wait_for_bit_change(const struct hdmi_reg idx, return val; } -static int hdmi_runtime_get(void) -{ - int r; - - DSSDBG("hdmi_runtime_get\n"); - - r = pm_runtime_get_sync(&hdmi.pdev->dev); - WARN_ON(r < 0); - return r < 0 ? r : 0; -} - -static void hdmi_runtime_put(void) -{ - int r; - - DSSDBG("hdmi_runtime_put\n"); - - r = pm_runtime_put(&hdmi.pdev->dev); - WARN_ON(r < 0); -} - int hdmi_init_display(struct omap_dss_device *dssdev) { DSSDBG("init_display\n"); @@ -338,11 +311,30 @@ static int hdmi_phy_init(void) return 0; } +static int hdmi_wait_softreset(void) +{ + /* reset W1 */ + REG_FLD_MOD(HDMI_WP_SYSCONFIG, 0x1, 0, 0); + + /* wait till SOFTRESET == 0 */ + if (hdmi_wait_for_bit_change(HDMI_WP_SYSCONFIG, 0, 0, 0) != 0) { + DSSERR("sysconfig reset failed\n"); + return -ETIMEDOUT; + } + + return 0; +} + static int hdmi_pll_program(struct hdmi_pll_info *fmt) { u16 r = 0; enum hdmi_clk_refsel refsel; + /* wait for wrapper reset */ + r = hdmi_wait_softreset(); + if (r) + return r; + r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF); if (r) return r; @@ -1072,7 +1064,7 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, unsigned long clkin, refclk; u32 mf; - clkin = clk_get_rate(hdmi.sys_clk) / 10000; + clkin = dss_clk_get_rate(DSS_CLK_SYSCK) / 10000; /* * Input clock is predivided by N + 1 * out put of which is reference clk @@ -1106,6 +1098,16 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd); } +static void hdmi_enable_clocks(int enable) +{ + if (enable) + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK | + DSS_CLK_SYSCK | DSS_CLK_VIDFCK); + else + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK | + DSS_CLK_SYSCK | DSS_CLK_VIDFCK); +} + static int hdmi_power_on(struct omap_dss_device *dssdev) { int r, code = 0; @@ -1113,9 +1115,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) struct omap_video_timings *p; unsigned long phy; - r = hdmi_runtime_get(); - if (r) - return r; + hdmi_enable_clocks(1); dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0); @@ -1180,7 +1180,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) return 0; err: - hdmi_runtime_put(); + hdmi_enable_clocks(0); return -EIO; } @@ -1191,7 +1191,7 @@ static void hdmi_power_off(struct omap_dss_device *dssdev) hdmi_wp_video_start(0); hdmi_phy_off(); hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF); - hdmi_runtime_put(); + hdmi_enable_clocks(0); hdmi.edid_set = 0; } @@ -1686,43 +1686,14 @@ static struct snd_soc_dai_driver hdmi_codec_dai_drv = { }; #endif -static int hdmi_get_clocks(struct platform_device *pdev) -{ - struct clk *clk; - - clk = clk_get(&pdev->dev, "sys_clk"); - if (IS_ERR(clk)) { - DSSERR("can't get sys_clk\n"); - return PTR_ERR(clk); - } - - hdmi.sys_clk = clk; - - clk = clk_get(&pdev->dev, "hdmi_clk"); - if (IS_ERR(clk)) { - DSSERR("can't get hdmi_clk\n"); - clk_put(hdmi.sys_clk); - return PTR_ERR(clk); - } - - hdmi.hdmi_clk = clk; - - return 0; -} - -static void hdmi_put_clocks(void) -{ - if (hdmi.sys_clk) - clk_put(hdmi.sys_clk); - if (hdmi.hdmi_clk) - clk_put(hdmi.hdmi_clk); -} - /* HDMI HW IP initialisation */ static int omapdss_hdmihw_probe(struct platform_device *pdev) { struct resource *hdmi_mem; - int r; +#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ + defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) + int ret; +#endif hdmi.pdata = pdev->dev.platform_data; hdmi.pdev = pdev; @@ -1742,25 +1713,17 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) return -ENOMEM; } - r = hdmi_get_clocks(pdev); - if (r) { - iounmap(hdmi.base_wp); - return r; - } - - pm_runtime_enable(&pdev->dev); - hdmi_panel_init(); #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) /* Register ASoC codec DAI */ - r = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv, + ret = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv, &hdmi_codec_dai_drv, 1); - if (r) { + if (ret) { DSSERR("can't register ASoC HDMI audio codec\n"); - return r; + return ret; } #endif return 0; @@ -1775,62 +1738,17 @@ static int omapdss_hdmihw_remove(struct platform_device *pdev) snd_soc_unregister_codec(&pdev->dev); #endif - pm_runtime_disable(&pdev->dev); - - hdmi_put_clocks(); - iounmap(hdmi.base_wp); return 0; } -static int hdmi_runtime_suspend(struct device *dev) -{ - clk_disable(hdmi.hdmi_clk); - clk_disable(hdmi.sys_clk); - - dispc_runtime_put(); - dss_runtime_put(); - - return 0; -} - -static int hdmi_runtime_resume(struct device *dev) -{ - int r; - - r = dss_runtime_get(); - if (r < 0) - goto err_get_dss; - - r = dispc_runtime_get(); - if (r < 0) - goto err_get_dispc; - - - clk_enable(hdmi.sys_clk); - clk_enable(hdmi.hdmi_clk); - - return 0; - -err_get_dispc: - dss_runtime_put(); -err_get_dss: - return r; -} - -static const struct dev_pm_ops hdmi_pm_ops = { - .runtime_suspend = hdmi_runtime_suspend, - .runtime_resume = hdmi_runtime_resume, -}; - static struct platform_driver omapdss_hdmihw_driver = { .probe = omapdss_hdmihw_probe, .remove = omapdss_hdmihw_remove, .driver = { .name = "omapdss_hdmi", .owner = THIS_MODULE, - .pm = &hdmi_pm_ops, }, }; diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index c6d26c6e697..9aeea50e33f 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -416,6 +416,8 @@ struct overlay_cache_data { enum omap_burst_size burst_size; u32 fifo_low; u32 fifo_high; + + bool manual_update; }; struct manager_cache_data { @@ -435,6 +437,7 @@ struct manager_cache_data { bool alpha_enabled; + bool manual_upd_display; bool manual_update; bool do_manual_update; @@ -536,15 +539,24 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) return 0; - if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) - return 0; - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; } else { - irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? - DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2; + if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { + enum omap_dss_update_mode mode; + mode = dssdev->driver->get_update_mode(dssdev); + if (mode != OMAP_DSS_UPDATE_AUTO) + return 0; + + irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? + DISPC_IRQ_FRAMEDONE + : DISPC_IRQ_FRAMEDONE2; + } else { + irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? + DISPC_IRQ_VSYNC + : DISPC_IRQ_VSYNC2; + } } mc = &dss_cache.manager_cache[mgr->id]; @@ -605,15 +617,24 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) return 0; - if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) - return 0; - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; } else { - irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? - DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2; + if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { + enum omap_dss_update_mode mode; + mode = dssdev->driver->get_update_mode(dssdev); + if (mode != OMAP_DSS_UPDATE_AUTO) + return 0; + + irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? + DISPC_IRQ_FRAMEDONE + : DISPC_IRQ_FRAMEDONE2; + } else { + irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? + DISPC_IRQ_VSYNC + : DISPC_IRQ_VSYNC2; + } } oc = &dss_cache.overlay_cache[ovl->id]; @@ -742,7 +763,7 @@ static int configure_overlay(enum omap_plane plane) orig_outw = outw; orig_outh = outh; - if (mc->manual_update && mc->do_manual_update) { + if (c->manual_update && mc->do_manual_update) { unsigned bpp; unsigned scale_x_m = w, scale_x_d = outw; unsigned scale_y_m = h, scale_y_d = outh; @@ -907,7 +928,7 @@ static int configure_dispc(void) if (!oc->dirty) continue; - if (mc->manual_update && !mc->do_manual_update) + if (oc->manual_update && !mc->do_manual_update) continue; if (mgr_busy[oc->channel]) { @@ -955,7 +976,7 @@ static int configure_dispc(void) /* We don't need GO with manual update display. LCD iface will * always be turned off after frame, and new settings will be * taken in to use at next update */ - if (!mc->manual_update) + if (!mc->manual_upd_display) dispc_go(i); } @@ -1215,10 +1236,6 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); - r = dispc_runtime_get(); - if (r) - return r; - spin_lock_irqsave(&dss_cache.lock, flags); /* Configure overlays */ @@ -1285,6 +1302,11 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) oc->enabled = true; + oc->manual_update = + dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE && + dssdev->driver->get_update_mode(dssdev) != + OMAP_DSS_UPDATE_AUTO; + ++num_planes_enabled; } @@ -1319,8 +1341,13 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) mc->trans_enabled = mgr->info.trans_enabled; mc->alpha_enabled = mgr->info.alpha_enabled; - mc->manual_update = + mc->manual_upd_display = dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; + + mc->manual_update = + dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE && + dssdev->driver->get_update_mode(dssdev) != + OMAP_DSS_UPDATE_AUTO; } /* XXX TODO: Try to get fifomerge working. The problem is that it @@ -1382,6 +1409,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) } r = 0; + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); if (!dss_cache.irq_enabled) { u32 mask; @@ -1394,11 +1422,10 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) dss_cache.irq_enabled = true; } configure_dispc(); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); spin_unlock_irqrestore(&dss_cache.lock, flags); - dispc_runtime_put(); - return r; } diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index c84380c53c3..0f08025b1f0 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -84,42 +84,32 @@ static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, old_mgr = ovl->manager; - r = dispc_runtime_get(); - if (r) - return r; - /* detach old manager */ if (old_mgr) { r = ovl->unset_manager(ovl); if (r) { DSSERR("detach failed\n"); - goto err; + return r; } r = old_mgr->apply(old_mgr); if (r) - goto err; + return r; } if (mgr) { r = ovl->set_manager(ovl, mgr); if (r) { DSSERR("Failed to attach overlay\n"); - goto err; + return r; } r = mgr->apply(mgr); if (r) - goto err; + return r; } - dispc_runtime_put(); - return size; - -err: - dispc_runtime_put(); - return r; } static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) @@ -248,9 +238,6 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, u8 alpha; struct omap_overlay_info info; - if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) - return -ENODEV; - r = kstrtou8(buf, 0, &alpha); if (r) return r; @@ -517,6 +504,7 @@ static int omap_dss_set_manager(struct omap_overlay *ovl, ovl->manager = mgr; + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); /* XXX: When there is an overlay on a DSI manual update display, and * the overlay is first disabled, then moved to tv, and enabled, we * seem to get SYNC_LOST_DIGIT error. @@ -530,6 +518,7 @@ static int omap_dss_set_manager(struct omap_overlay *ovl, * the overlay, but before moving the overlay to TV. */ dispc_set_channel_out(ovl->id, mgr->id); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); return 0; } @@ -730,8 +719,6 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) } if (mgr) { - dispc_runtime_get(); - for (i = 0; i < dss_feat_get_num_ovls(); i++) { struct omap_overlay *ovl; ovl = omap_dss_get_overlay(i); @@ -741,8 +728,6 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) omap_dss_set_manager(ovl, mgr); } } - - dispc_runtime_put(); } } diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index c57e3fbf239..c06fbe0bc67 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -33,8 +33,6 @@ #include <linux/hrtimer.h> #include <linux/seq_file.h> #include <linux/semaphore.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> #include <video/omapdss.h> #include "dss.h" @@ -122,25 +120,12 @@ static inline u32 rfbi_read_reg(const struct rfbi_reg idx) return __raw_readl(rfbi.base + idx.idx); } -static int rfbi_runtime_get(void) +static void rfbi_enable_clocks(bool enable) { - int r; - - DSSDBG("rfbi_runtime_get\n"); - - r = pm_runtime_get_sync(&rfbi.pdev->dev); - WARN_ON(r < 0); - return r < 0 ? r : 0; -} - -static void rfbi_runtime_put(void) -{ - int r; - - DSSDBG("rfbi_runtime_put\n"); - - r = pm_runtime_put(&rfbi.pdev->dev); - WARN_ON(r < 0); + if (enable) + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); + else + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); } void rfbi_bus_lock(void) @@ -820,8 +805,7 @@ void rfbi_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r)) - if (rfbi_runtime_get()) - return; + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); DUMPREG(RFBI_REVISION); DUMPREG(RFBI_SYSCONFIG); @@ -852,7 +836,7 @@ void rfbi_dump_regs(struct seq_file *s) DUMPREG(RFBI_VSYNC_WIDTH); DUMPREG(RFBI_HSYNC_WIDTH); - rfbi_runtime_put(); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); #undef DUMPREG } @@ -860,9 +844,7 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) { int r; - r = rfbi_runtime_get(); - if (r) - return r; + rfbi_enable_clocks(1); r = omap_dss_start_device(dssdev); if (r) { @@ -897,7 +879,6 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) err1: omap_dss_stop_device(dssdev); err0: - rfbi_runtime_put(); return r; } EXPORT_SYMBOL(omapdss_rfbi_display_enable); @@ -908,7 +889,7 @@ void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev) DISPC_IRQ_FRAMEDONE); omap_dss_stop_device(dssdev); - rfbi_runtime_put(); + rfbi_enable_clocks(0); } EXPORT_SYMBOL(omapdss_rfbi_display_disable); @@ -923,9 +904,8 @@ int rfbi_init_display(struct omap_dss_device *dssdev) static int omap_rfbihw_probe(struct platform_device *pdev) { u32 rev; + u32 l; struct resource *rfbi_mem; - struct clk *clk; - int r; rfbi.pdev = pdev; @@ -934,99 +914,46 @@ static int omap_rfbihw_probe(struct platform_device *pdev) rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0); if (!rfbi_mem) { DSSERR("can't get IORESOURCE_MEM RFBI\n"); - r = -EINVAL; - goto err_ioremap; + return -EINVAL; } rfbi.base = ioremap(rfbi_mem->start, resource_size(rfbi_mem)); if (!rfbi.base) { DSSERR("can't ioremap RFBI\n"); - r = -ENOMEM; - goto err_ioremap; + return -ENOMEM; } - pm_runtime_enable(&pdev->dev); - - r = rfbi_runtime_get(); - if (r) - goto err_get_rfbi; + rfbi_enable_clocks(1); msleep(10); - clk = clk_get(&pdev->dev, "rfbi_iclk"); - if (IS_ERR(clk)) { - DSSERR("can't get rfbi_iclk\n"); - r = PTR_ERR(clk); - goto err_get_ick; - } - - rfbi.l4_khz = clk_get_rate(clk) / 1000; + rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000; - clk_put(clk); + /* Enable autoidle and smart-idle */ + l = rfbi_read_reg(RFBI_SYSCONFIG); + l |= (1 << 0) | (2 << 3); + rfbi_write_reg(RFBI_SYSCONFIG, l); rev = rfbi_read_reg(RFBI_REVISION); dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - rfbi_runtime_put(); + rfbi_enable_clocks(0); return 0; - -err_get_ick: - rfbi_runtime_put(); -err_get_rfbi: - pm_runtime_disable(&pdev->dev); - iounmap(rfbi.base); -err_ioremap: - return r; } static int omap_rfbihw_remove(struct platform_device *pdev) { - pm_runtime_disable(&pdev->dev); iounmap(rfbi.base); return 0; } -static int rfbi_runtime_suspend(struct device *dev) -{ - dispc_runtime_put(); - dss_runtime_put(); - - return 0; -} - -static int rfbi_runtime_resume(struct device *dev) -{ - int r; - - r = dss_runtime_get(); - if (r < 0) - goto err_get_dss; - - r = dispc_runtime_get(); - if (r < 0) - goto err_get_dispc; - - return 0; - -err_get_dispc: - dss_runtime_put(); -err_get_dss: - return r; -} - -static const struct dev_pm_ops rfbi_pm_ops = { - .runtime_suspend = rfbi_runtime_suspend, - .runtime_resume = rfbi_runtime_resume, -}; - static struct platform_driver omap_rfbihw_driver = { .probe = omap_rfbihw_probe, .remove = omap_rfbihw_remove, .driver = { .name = "omapdss_rfbi", .owner = THIS_MODULE, - .pm = &rfbi_pm_ops, }, }; diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 3a688c871a4..0bd4b0350f8 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -20,11 +20,13 @@ #define DSS_SUBSYS_NAME "SDI" #include <linux/kernel.h> +#include <linux/clk.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/regulator/consumer.h> #include <video/omapdss.h> +#include <plat/cpu.h> #include "dss.h" static struct { @@ -58,20 +60,14 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); - goto err_start_dev; + goto err0; } r = regulator_enable(sdi.vdds_sdi_reg); if (r) - goto err_reg_enable; + goto err1; - r = dss_runtime_get(); - if (r) - goto err_get_dss; - - r = dispc_runtime_get(); - if (r) - goto err_get_dispc; + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); sdi_basic_init(dssdev); @@ -84,7 +80,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) r = dss_calc_clock_div(1, t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); if (r) - goto err_calc_clock_div; + goto err2; fck = dss_cinfo.fck; lck_div = dispc_cinfo.lck_div; @@ -105,34 +101,27 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) r = dss_set_clock_div(&dss_cinfo); if (r) - goto err_set_dss_clock_div; + goto err2; r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) - goto err_set_dispc_clock_div; + goto err2; dss_sdi_init(dssdev->phy.sdi.datapairs); r = dss_sdi_enable(); if (r) - goto err_sdi_enable; + goto err1; mdelay(2); dssdev->manager->enable(dssdev->manager); return 0; - -err_sdi_enable: -err_set_dispc_clock_div: -err_set_dss_clock_div: -err_calc_clock_div: - dispc_runtime_put(); -err_get_dispc: - dss_runtime_put(); -err_get_dss: +err2: + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); regulator_disable(sdi.vdds_sdi_reg); -err_reg_enable: +err1: omap_dss_stop_device(dssdev); -err_start_dev: +err0: return r; } EXPORT_SYMBOL(omapdss_sdi_display_enable); @@ -143,8 +132,7 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) dss_sdi_disable(); - dispc_runtime_put(); - dss_runtime_put(); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); regulator_disable(sdi.vdds_sdi_reg); diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index f75159dc7f7..980f919ed98 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -33,13 +33,11 @@ #include <linux/seq_file.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> -#include <linux/pm_runtime.h> #include <video/omapdss.h> #include <plat/cpu.h> #include "dss.h" -#include "dss_features.h" /* Venc registers */ #define VENC_REV_ID 0x00 @@ -294,9 +292,6 @@ static struct { struct mutex venc_lock; u32 wss_data; struct regulator *vdda_dac_reg; - - struct clk *tv_clk; - struct clk *tv_dac_clk; } venc; static inline void venc_write_reg(int idx, u32 val) @@ -385,25 +380,14 @@ static void venc_reset(void) #endif } -static int venc_runtime_get(void) -{ - int r; - - DSSDBG("venc_runtime_get\n"); - - r = pm_runtime_get_sync(&venc.pdev->dev); - WARN_ON(r < 0); - return r < 0 ? r : 0; -} - -static void venc_runtime_put(void) +static void venc_enable_clocks(int enable) { - int r; - - DSSDBG("venc_runtime_put\n"); - - r = pm_runtime_put(&venc.pdev->dev); - WARN_ON(r < 0); + if (enable) + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK | + DSS_CLK_VIDFCK); + else + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK | + DSS_CLK_VIDFCK); } static const struct venc_config *venc_timings_to_config( @@ -422,6 +406,8 @@ static void venc_power_on(struct omap_dss_device *dssdev) { u32 l; + venc_enable_clocks(1); + venc_reset(); venc_write_config(venc_timings_to_config(&dssdev->panel.timings)); @@ -462,6 +448,8 @@ static void venc_power_off(struct omap_dss_device *dssdev) dssdev->platform_disable(dssdev); regulator_disable(venc.vdda_dac_reg); + + venc_enable_clocks(0); } @@ -499,10 +487,6 @@ static int venc_panel_enable(struct omap_dss_device *dssdev) goto err1; } - r = venc_runtime_get(); - if (r) - goto err1; - venc_power_on(dssdev); venc.wss_data = 0; @@ -536,8 +520,6 @@ static void venc_panel_disable(struct omap_dss_device *dssdev) venc_power_off(dssdev); - venc_runtime_put(); - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; omap_dss_stop_device(dssdev); @@ -556,6 +538,20 @@ static int venc_panel_resume(struct omap_dss_device *dssdev) return venc_panel_enable(dssdev); } +static enum omap_dss_update_mode venc_get_update_mode( + struct omap_dss_device *dssdev) +{ + return OMAP_DSS_UPDATE_AUTO; +} + +static int venc_set_update_mode(struct omap_dss_device *dssdev, + enum omap_dss_update_mode mode) +{ + if (mode != OMAP_DSS_UPDATE_AUTO) + return -EINVAL; + return 0; +} + static void venc_get_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { @@ -602,7 +598,6 @@ static u32 venc_get_wss(struct omap_dss_device *dssdev) static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) { const struct venc_config *config; - int r; DSSDBG("venc_set_wss\n"); @@ -613,19 +608,16 @@ static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) /* Invert due to VENC_L21_WC_CTL:INV=1 */ venc.wss_data = (wss ^ 0xfffff) << 8; - r = venc_runtime_get(); - if (r) - goto err; + venc_enable_clocks(1); venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data | venc.wss_data); - venc_runtime_put(); + venc_enable_clocks(0); -err: mutex_unlock(&venc.venc_lock); - return r; + return 0; } static struct omap_dss_driver venc_driver = { @@ -640,6 +632,9 @@ static struct omap_dss_driver venc_driver = { .get_resolution = omapdss_default_get_resolution, .get_recommended_bpp = omapdss_default_get_recommended_bpp, + .set_update_mode = venc_set_update_mode, + .get_update_mode = venc_get_update_mode, + .get_timings = venc_get_timings, .set_timings = venc_set_timings, .check_timings = venc_check_timings, @@ -678,8 +673,7 @@ void venc_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r)) - if (venc_runtime_get()) - return; + venc_enable_clocks(1); DUMPREG(VENC_F_CONTROL); DUMPREG(VENC_VIDOUT_CTRL); @@ -723,53 +717,16 @@ void venc_dump_regs(struct seq_file *s) DUMPREG(VENC_OUTPUT_CONTROL); DUMPREG(VENC_OUTPUT_TEST); - venc_runtime_put(); + venc_enable_clocks(0); #undef DUMPREG } -static int venc_get_clocks(struct platform_device *pdev) -{ - struct clk *clk; - - clk = clk_get(&pdev->dev, "tv_clk"); - if (IS_ERR(clk)) { - DSSERR("can't get tv_clk\n"); - return PTR_ERR(clk); - } - - venc.tv_clk = clk; - - if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) { - clk = clk_get(&pdev->dev, "tv_dac_clk"); - if (IS_ERR(clk)) { - DSSERR("can't get tv_dac_clk\n"); - clk_put(venc.tv_clk); - return PTR_ERR(clk); - } - } else { - clk = NULL; - } - - venc.tv_dac_clk = clk; - - return 0; -} - -static void venc_put_clocks(void) -{ - if (venc.tv_clk) - clk_put(venc.tv_clk); - if (venc.tv_dac_clk) - clk_put(venc.tv_dac_clk); -} - /* VENC HW IP initialisation */ static int omap_venchw_probe(struct platform_device *pdev) { u8 rev_id; struct resource *venc_mem; - int r; venc.pdev = pdev; @@ -780,40 +737,22 @@ static int omap_venchw_probe(struct platform_device *pdev) venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0); if (!venc_mem) { DSSERR("can't get IORESOURCE_MEM VENC\n"); - r = -EINVAL; - goto err_ioremap; + return -EINVAL; } venc.base = ioremap(venc_mem->start, resource_size(venc_mem)); if (!venc.base) { DSSERR("can't ioremap VENC\n"); - r = -ENOMEM; - goto err_ioremap; + return -ENOMEM; } - r = venc_get_clocks(pdev); - if (r) - goto err_get_clk; - - pm_runtime_enable(&pdev->dev); - - r = venc_runtime_get(); - if (r) - goto err_get_venc; + venc_enable_clocks(1); rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff); dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id); - venc_runtime_put(); + venc_enable_clocks(0); return omap_dss_register_driver(&venc_driver); - -err_get_venc: - pm_runtime_disable(&pdev->dev); - venc_put_clocks(); -err_get_clk: - iounmap(venc.base); -err_ioremap: - return r; } static int omap_venchw_remove(struct platform_device *pdev) @@ -824,61 +763,16 @@ static int omap_venchw_remove(struct platform_device *pdev) } omap_dss_unregister_driver(&venc_driver); - pm_runtime_disable(&pdev->dev); - venc_put_clocks(); - iounmap(venc.base); return 0; } -static int venc_runtime_suspend(struct device *dev) -{ - if (venc.tv_dac_clk) - clk_disable(venc.tv_dac_clk); - clk_disable(venc.tv_clk); - - dispc_runtime_put(); - dss_runtime_put(); - - return 0; -} - -static int venc_runtime_resume(struct device *dev) -{ - int r; - - r = dss_runtime_get(); - if (r < 0) - goto err_get_dss; - - r = dispc_runtime_get(); - if (r < 0) - goto err_get_dispc; - - clk_enable(venc.tv_clk); - if (venc.tv_dac_clk) - clk_enable(venc.tv_dac_clk); - - return 0; - -err_get_dispc: - dss_runtime_put(); -err_get_dss: - return r; -} - -static const struct dev_pm_ops venc_pm_ops = { - .runtime_suspend = venc_runtime_suspend, - .runtime_resume = venc_runtime_resume, -}; - static struct platform_driver omap_venchw_driver = { .probe = omap_venchw_probe, .remove = omap_venchw_remove, .driver = { .name = "omapdss_venc", .owner = THIS_MODULE, - .pm = &venc_pm_ops, }, }; diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 6b1ac23dbbd..cff450392b7 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -316,67 +316,67 @@ int omapfb_update_window(struct fb_info *fbi, } EXPORT_SYMBOL(omapfb_update_window); -int omapfb_set_update_mode(struct fb_info *fbi, +static int omapfb_set_update_mode(struct fb_info *fbi, enum omapfb_update_mode mode) { struct omap_dss_device *display = fb2display(fbi); - struct omapfb_info *ofbi = FB2OFB(fbi); - struct omapfb2_device *fbdev = ofbi->fbdev; - struct omapfb_display_data *d; + enum omap_dss_update_mode um; int r; - if (!display) - return -EINVAL; - - if (mode != OMAPFB_AUTO_UPDATE && mode != OMAPFB_MANUAL_UPDATE) + if (!display || !display->driver->set_update_mode) return -EINVAL; - omapfb_lock(fbdev); - - d = get_display_data(fbdev, display); - - if (d->update_mode == mode) { - omapfb_unlock(fbdev); - return 0; - } + switch (mode) { + case OMAPFB_UPDATE_DISABLED: + um = OMAP_DSS_UPDATE_DISABLED; + break; - r = 0; + case OMAPFB_AUTO_UPDATE: + um = OMAP_DSS_UPDATE_AUTO; + break; - if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { - if (mode == OMAPFB_AUTO_UPDATE) - omapfb_start_auto_update(fbdev, display); - else /* MANUAL_UPDATE */ - omapfb_stop_auto_update(fbdev, display); + case OMAPFB_MANUAL_UPDATE: + um = OMAP_DSS_UPDATE_MANUAL; + break; - d->update_mode = mode; - } else { /* AUTO_UPDATE */ - if (mode == OMAPFB_MANUAL_UPDATE) - r = -EINVAL; + default: + return -EINVAL; } - omapfb_unlock(fbdev); + r = display->driver->set_update_mode(display, um); return r; } -int omapfb_get_update_mode(struct fb_info *fbi, +static int omapfb_get_update_mode(struct fb_info *fbi, enum omapfb_update_mode *mode) { struct omap_dss_device *display = fb2display(fbi); - struct omapfb_info *ofbi = FB2OFB(fbi); - struct omapfb2_device *fbdev = ofbi->fbdev; - struct omapfb_display_data *d; + enum omap_dss_update_mode m; if (!display) return -EINVAL; - omapfb_lock(fbdev); - - d = get_display_data(fbdev, display); + if (!display->driver->get_update_mode) { + *mode = OMAPFB_AUTO_UPDATE; + return 0; + } - *mode = d->update_mode; + m = display->driver->get_update_mode(display); - omapfb_unlock(fbdev); + switch (m) { + case OMAP_DSS_UPDATE_DISABLED: + *mode = OMAPFB_UPDATE_DISABLED; + break; + case OMAP_DSS_UPDATE_AUTO: + *mode = OMAPFB_AUTO_UPDATE; + break; + case OMAP_DSS_UPDATE_MANUAL: + *mode = OMAPFB_MANUAL_UPDATE; + break; + default: + BUG(); + } return 0; } diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 602b71a92d3..505bc12a303 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -46,10 +46,6 @@ static char *def_vram; static int def_vrfb; static int def_rotate; static int def_mirror; -static bool auto_update; -static unsigned int auto_update_freq; -module_param(auto_update, bool, 0); -module_param(auto_update_freq, uint, 0644); #ifdef DEBUG unsigned int omapfb_debug; @@ -1246,7 +1242,6 @@ static int omapfb_blank(int blank, struct fb_info *fbi) struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_dss_device *display = fb2display(fbi); - struct omapfb_display_data *d; int r = 0; if (!display) @@ -1254,8 +1249,6 @@ static int omapfb_blank(int blank, struct fb_info *fbi) omapfb_lock(fbdev); - d = get_display_data(fbdev, display); - switch (blank) { case FB_BLANK_UNBLANK: if (display->state != OMAP_DSS_DISPLAY_SUSPENDED) @@ -1264,11 +1257,6 @@ static int omapfb_blank(int blank, struct fb_info *fbi) if (display->driver->resume) r = display->driver->resume(display); - if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) && - d->update_mode == OMAPFB_AUTO_UPDATE && - !d->auto_update_work_enabled) - omapfb_start_auto_update(fbdev, display); - break; case FB_BLANK_NORMAL: @@ -1280,9 +1268,6 @@ static int omapfb_blank(int blank, struct fb_info *fbi) if (display->state != OMAP_DSS_DISPLAY_ACTIVE) goto exit; - if (d->auto_update_work_enabled) - omapfb_stop_auto_update(fbdev, display); - if (display->driver->suspend) r = display->driver->suspend(display); @@ -1739,78 +1724,6 @@ err: return r; } -static void omapfb_auto_update_work(struct work_struct *work) -{ - struct omap_dss_device *dssdev; - struct omap_dss_driver *dssdrv; - struct omapfb_display_data *d; - u16 w, h; - unsigned int freq; - struct omapfb2_device *fbdev; - - d = container_of(work, struct omapfb_display_data, - auto_update_work.work); - - dssdev = d->dssdev; - dssdrv = dssdev->driver; - fbdev = d->fbdev; - - if (!dssdrv || !dssdrv->update) - return; - - if (dssdrv->sync) - dssdrv->sync(dssdev); - - dssdrv->get_resolution(dssdev, &w, &h); - dssdrv->update(dssdev, 0, 0, w, h); - - freq = auto_update_freq; - if (freq == 0) - freq = 20; - queue_delayed_work(fbdev->auto_update_wq, - &d->auto_update_work, HZ / freq); -} - -void omapfb_start_auto_update(struct omapfb2_device *fbdev, - struct omap_dss_device *display) -{ - struct omapfb_display_data *d; - - if (fbdev->auto_update_wq == NULL) { - struct workqueue_struct *wq; - - wq = create_singlethread_workqueue("omapfb_auto_update"); - - if (wq == NULL) { - dev_err(fbdev->dev, "Failed to create workqueue for " - "auto-update\n"); - return; - } - - fbdev->auto_update_wq = wq; - } - - d = get_display_data(fbdev, display); - - INIT_DELAYED_WORK(&d->auto_update_work, omapfb_auto_update_work); - - d->auto_update_work_enabled = true; - - omapfb_auto_update_work(&d->auto_update_work.work); -} - -void omapfb_stop_auto_update(struct omapfb2_device *fbdev, - struct omap_dss_device *display) -{ - struct omapfb_display_data *d; - - d = get_display_data(fbdev, display); - - cancel_delayed_work_sync(&d->auto_update_work); - - d->auto_update_work_enabled = false; -} - /* initialize fb_info, var, fix to something sane based on the display */ static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi) { @@ -1945,21 +1858,10 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev) } for (i = 0; i < fbdev->num_displays; i++) { - struct omap_dss_device *dssdev = fbdev->displays[i].dssdev; - - if (fbdev->displays[i].auto_update_work_enabled) - omapfb_stop_auto_update(fbdev, dssdev); - - if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) - dssdev->driver->disable(dssdev); - - omap_dss_put_device(dssdev); - } + if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED) + fbdev->displays[i]->driver->disable(fbdev->displays[i]); - if (fbdev->auto_update_wq != NULL) { - flush_workqueue(fbdev->auto_update_wq); - destroy_workqueue(fbdev->auto_update_wq); - fbdev->auto_update_wq = NULL; + omap_dss_put_device(fbdev->displays[i]); } dev_set_drvdata(fbdev->dev, NULL); @@ -2182,14 +2084,14 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev, int r; u8 bpp; struct omap_video_timings timings, temp_timings; - struct omapfb_display_data *d; r = omapfb_mode_to_timings(mode_str, &timings, &bpp); if (r) return r; - d = get_display_data(fbdev, display); - d->bpp_override = bpp; + fbdev->bpp_overrides[fbdev->num_bpp_overrides].dssdev = display; + fbdev->bpp_overrides[fbdev->num_bpp_overrides].bpp = bpp; + ++fbdev->num_bpp_overrides; if (display->driver->check_timings) { r = display->driver->check_timings(display, &timings); @@ -2215,14 +2117,14 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev, static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev, struct omap_dss_device *dssdev) { - struct omapfb_display_data *d; + int i; BUG_ON(dssdev->driver->get_recommended_bpp == NULL); - d = get_display_data(fbdev, dssdev); - - if (d->bpp_override != 0) - return d->bpp_override; + for (i = 0; i < fbdev->num_bpp_overrides; ++i) { + if (dssdev == fbdev->bpp_overrides[i].dssdev) + return fbdev->bpp_overrides[i].bpp; + } return dssdev->driver->get_recommended_bpp(dssdev); } @@ -2254,9 +2156,9 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev) display = NULL; for (i = 0; i < fbdev->num_displays; ++i) { - if (strcmp(fbdev->displays[i].dssdev->name, + if (strcmp(fbdev->displays[i]->name, display_str) == 0) { - display = fbdev->displays[i].dssdev; + display = fbdev->displays[i]; break; } } @@ -2280,7 +2182,6 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, struct omap_dss_device *dssdev) { struct omap_dss_driver *dssdrv = dssdev->driver; - struct omapfb_display_data *d; int r; r = dssdrv->enable(dssdev); @@ -2290,20 +2191,8 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, return r; } - d = get_display_data(fbdev, dssdev); - - d->fbdev = fbdev; - if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { u16 w, h; - - if (auto_update) { - omapfb_start_auto_update(fbdev, dssdev); - d->update_mode = OMAPFB_AUTO_UPDATE; - } else { - d->update_mode = OMAPFB_MANUAL_UPDATE; - } - if (dssdrv->enable_te) { r = dssdrv->enable_te(dssdev, 1); if (r) { @@ -2312,6 +2201,16 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, } } + if (dssdrv->set_update_mode) { + r = dssdrv->set_update_mode(dssdev, + OMAP_DSS_UPDATE_MANUAL); + if (r) { + dev_err(fbdev->dev, + "Failed to set update mode\n"); + return r; + } + } + dssdrv->get_resolution(dssdev, &w, &h); r = dssdrv->update(dssdev, 0, 0, w, h); if (r) { @@ -2320,7 +2219,15 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, return r; } } else { - d->update_mode = OMAPFB_AUTO_UPDATE; + if (dssdrv->set_update_mode) { + r = dssdrv->set_update_mode(dssdev, + OMAP_DSS_UPDATE_AUTO); + if (r) { + dev_err(fbdev->dev, + "Failed to set update mode\n"); + return r; + } + } } return 0; @@ -2368,8 +2275,6 @@ static int omapfb_probe(struct platform_device *pdev) fbdev->num_displays = 0; dssdev = NULL; for_each_dss_dev(dssdev) { - struct omapfb_display_data *d; - omap_dss_get_device(dssdev); if (!dssdev->driver) { @@ -2377,12 +2282,7 @@ static int omapfb_probe(struct platform_device *pdev) r = -ENODEV; } - d = &fbdev->displays[fbdev->num_displays++]; - d->dssdev = dssdev; - if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) - d->update_mode = OMAPFB_MANUAL_UPDATE; - else - d->update_mode = OMAPFB_AUTO_UPDATE; + fbdev->displays[fbdev->num_displays++] = dssdev; } if (r) diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index 153bf1aceeb..2f5e817b2a9 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c @@ -518,39 +518,6 @@ static ssize_t show_virt(struct device *dev, return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr); } -static ssize_t show_upd_mode(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct fb_info *fbi = dev_get_drvdata(dev); - enum omapfb_update_mode mode; - int r; - - r = omapfb_get_update_mode(fbi, &mode); - - if (r) - return r; - - return snprintf(buf, PAGE_SIZE, "%u\n", (unsigned)mode); -} - -static ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct fb_info *fbi = dev_get_drvdata(dev); - unsigned mode; - int r; - - r = kstrtouint(buf, 0, &mode); - if (r) - return r; - - r = omapfb_set_update_mode(fbi, mode); - if (r) - return r; - - return count; -} - static struct device_attribute omapfb_attrs[] = { __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type, store_rotate_type), @@ -561,7 +528,6 @@ static struct device_attribute omapfb_attrs[] = { store_overlays_rotate), __ATTR(phys_addr, S_IRUGO, show_phys, NULL), __ATTR(virt_addr, S_IRUGO, show_virt, NULL), - __ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode), }; int omapfb_create_sysfs(struct omapfb2_device *fbdev) diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index fdf0edeccf4..aa1b1d97427 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h @@ -73,15 +73,6 @@ struct omapfb_info { bool mirror; }; -struct omapfb_display_data { - struct omapfb2_device *fbdev; - struct omap_dss_device *dssdev; - u8 bpp_override; - enum omapfb_update_mode update_mode; - bool auto_update_work_enabled; - struct delayed_work auto_update_work; -}; - struct omapfb2_device { struct device *dev; struct mutex mtx; @@ -95,13 +86,17 @@ struct omapfb2_device { struct omapfb2_mem_region regions[10]; unsigned num_displays; - struct omapfb_display_data displays[10]; + struct omap_dss_device *displays[10]; unsigned num_overlays; struct omap_overlay *overlays[10]; unsigned num_managers; struct omap_overlay_manager *managers[10]; - struct workqueue_struct *auto_update_wq; + unsigned num_bpp_overrides; + struct { + struct omap_dss_device *dssdev; + u8 bpp; + } bpp_overrides[10]; }; struct omapfb_colormode { @@ -133,13 +128,6 @@ int dss_mode_to_fb_mode(enum omap_color_mode dssmode, int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, u16 posx, u16 posy, u16 outw, u16 outh); -void omapfb_start_auto_update(struct omapfb2_device *fbdev, - struct omap_dss_device *display); -void omapfb_stop_auto_update(struct omapfb2_device *fbdev, - struct omap_dss_device *display); -int omapfb_get_update_mode(struct fb_info *fbi, enum omapfb_update_mode *mode); -int omapfb_set_update_mode(struct fb_info *fbi, enum omapfb_update_mode mode); - /* find the display connected to this fb, if any */ static inline struct omap_dss_device *fb2display(struct fb_info *fbi) { @@ -155,19 +143,6 @@ static inline struct omap_dss_device *fb2display(struct fb_info *fbi) return NULL; } -static inline struct omapfb_display_data *get_display_data( - struct omapfb2_device *fbdev, struct omap_dss_device *dssdev) -{ - int i; - - for (i = 0; i < fbdev->num_displays; ++i) - if (fbdev->displays[i].dssdev == dssdev) - return &fbdev->displays[i]; - - /* This should never happen */ - BUG(); -} - static inline void omapfb_lock(struct omapfb2_device *fbdev) { mutex_lock(&fbdev->mtx); |
