summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/dma/mxs-dma.c109
-rw-r--r--drivers/i2c/busses/i2c-mxs.c40
-rw-r--r--drivers/mmc/host/mxs-mmc.c48
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c51
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.h3
-rw-r--r--drivers/net/ethernet/freescale/fec.h1
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c18
-rw-r--r--drivers/spi/spi-davinci.c4
-rw-r--r--drivers/spi/spi-mxs.c60
-rw-r--r--drivers/tty/serial/mxs-auart.c52
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/mxsfb.c260
12 files changed, 272 insertions, 376 deletions
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index 8f6d30d37c45..b48a79c28845 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -27,6 +27,7 @@
#include <linux/stmp_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/of_dma.h>
#include <asm/irq.h>
@@ -139,6 +140,8 @@ struct mxs_dma_engine {
struct dma_device dma_device;
struct device_dma_parameters dma_parms;
struct mxs_dma_chan mxs_chans[MXS_DMA_CHANNELS];
+ struct platform_device *pdev;
+ unsigned int nr_channels;
};
struct mxs_dma_type {
@@ -350,10 +353,8 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
int ret;
- if (!data)
- return -EINVAL;
-
- mxs_chan->chan_irq = data->chan_irq;
+ if (data)
+ mxs_chan->chan_irq = data->chan_irq;
mxs_chan->ccw = dma_alloc_coherent(mxs_dma->dma_device.dev,
CCW_BLOCK_SIZE, &mxs_chan->ccw_phys,
@@ -665,8 +666,55 @@ err_out:
return ret;
}
+struct mxs_dma_filter_param {
+ struct device_node *of_node;
+ unsigned int chan_id;
+};
+
+static bool mxs_dma_filter_fn(struct dma_chan *chan, void *fn_param)
+{
+ struct mxs_dma_filter_param *param = fn_param;
+ struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+ struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+ int chan_irq;
+
+ if (mxs_dma->dma_device.dev->of_node != param->of_node)
+ return false;
+
+ if (chan->chan_id != param->chan_id)
+ return false;
+
+ chan_irq = platform_get_irq(mxs_dma->pdev, param->chan_id);
+ if (chan_irq < 0)
+ return false;
+
+ mxs_chan->chan_irq = chan_irq;
+
+ return true;
+}
+
+struct dma_chan *mxs_dma_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct mxs_dma_engine *mxs_dma = ofdma->of_dma_data;
+ dma_cap_mask_t mask = mxs_dma->dma_device.cap_mask;
+ struct mxs_dma_filter_param param;
+
+ if (dma_spec->args_count != 1)
+ return NULL;
+
+ param.of_node = ofdma->of_node;
+ param.chan_id = dma_spec->args[0];
+
+ if (param.chan_id >= mxs_dma->nr_channels)
+ return NULL;
+
+ return dma_request_channel(mask, mxs_dma_filter_fn, &param);
+}
+
static int __init mxs_dma_probe(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
const struct platform_device_id *id_entry;
const struct of_device_id *of_id;
const struct mxs_dma_type *dma_type;
@@ -674,10 +722,16 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
struct resource *iores;
int ret, i;
- mxs_dma = kzalloc(sizeof(*mxs_dma), GFP_KERNEL);
+ mxs_dma = devm_kzalloc(&pdev->dev, sizeof(*mxs_dma), GFP_KERNEL);
if (!mxs_dma)
return -ENOMEM;
+ ret = of_property_read_u32(np, "dma-channels", &mxs_dma->nr_channels);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read dma-channels\n");
+ return ret;
+ }
+
of_id = of_match_device(mxs_dma_dt_ids, &pdev->dev);
if (of_id)
id_entry = of_id->data;
@@ -689,24 +743,13 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
mxs_dma->dev_id = dma_type->id;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mxs_dma->base = devm_ioremap_resource(&pdev->dev, iores);
+ if (IS_ERR(mxs_dma->base))
+ return PTR_ERR(mxs_dma->base);
- if (!request_mem_region(iores->start, resource_size(iores),
- pdev->name)) {
- ret = -EBUSY;
- goto err_request_region;
- }
-
- mxs_dma->base = ioremap(iores->start, resource_size(iores));
- if (!mxs_dma->base) {
- ret = -ENOMEM;
- goto err_ioremap;
- }
-
- mxs_dma->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(mxs_dma->clk)) {
- ret = PTR_ERR(mxs_dma->clk);
- goto err_clk;
- }
+ mxs_dma->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(mxs_dma->clk))
+ return PTR_ERR(mxs_dma->clk);
dma_cap_set(DMA_SLAVE, mxs_dma->dma_device.cap_mask);
dma_cap_set(DMA_CYCLIC, mxs_dma->dma_device.cap_mask);
@@ -732,8 +775,9 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
ret = mxs_dma_init(mxs_dma);
if (ret)
- goto err_init;
+ return ret;
+ mxs_dma->pdev = pdev;
mxs_dma->dma_device.dev = &pdev->dev;
/* mxs_dma gets 65535 bytes maximum sg size */
@@ -751,22 +795,19 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
ret = dma_async_device_register(&mxs_dma->dma_device);
if (ret) {
dev_err(mxs_dma->dma_device.dev, "unable to register\n");
- goto err_init;
+ return ret;
+ }
+
+ ret = of_dma_controller_register(np, mxs_dma_xlate, mxs_dma);
+ if (ret) {
+ dev_err(mxs_dma->dma_device.dev,
+ "failed to register controller\n");
+ dma_async_device_unregister(&mxs_dma->dma_device);
}
dev_info(mxs_dma->dma_device.dev, "initialized\n");
return 0;
-
-err_init:
- clk_put(mxs_dma->clk);
-err_clk:
- iounmap(mxs_dma->base);
-err_ioremap:
- release_mem_region(iores->start, resource_size(iores));
-err_request_region:
- kfree(mxs_dma);
- return ret;
}
static struct platform_driver mxs_dma_driver = {
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index c67d89fc6254..2039f230482d 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -31,7 +31,6 @@
#include <linux/of_i2c.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
-#include <linux/fsl/mxs-dma.h>
#define DRIVER_NAME "mxs-i2c"
@@ -118,9 +117,7 @@ struct mxs_i2c_dev {
uint32_t timing1;
/* DMA support components */
- int dma_channel;
struct dma_chan *dmach;
- struct mxs_dma_data dma_data;
uint32_t pio_data[2];
uint32_t addr_data;
struct scatterlist sg_io[2];
@@ -581,21 +578,6 @@ static const struct i2c_algorithm mxs_i2c_algo = {
.functionality = mxs_i2c_func,
};
-static bool mxs_i2c_dma_filter(struct dma_chan *chan, void *param)
-{
- struct mxs_i2c_dev *i2c = param;
-
- if (!mxs_dma_is_apbx(chan))
- return false;
-
- if (chan->chan_id != i2c->dma_channel)
- return false;
-
- chan->private = &i2c->dma_data;
-
- return true;
-}
-
static void mxs_i2c_derive_timing(struct mxs_i2c_dev *i2c, int speed)
{
/* The I2C block clock run at 24MHz */
@@ -640,17 +622,6 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
struct device_node *node = dev->of_node;
int ret;
- /*
- * TODO: This is a temporary solution and should be changed
- * to use generic DMA binding later when the helpers get in.
- */
- ret = of_property_read_u32(node, "fsl,i2c-dma-channel",
- &i2c->dma_channel);
- if (ret) {
- dev_err(dev, "Failed to get DMA channel!\n");
- return -ENODEV;
- }
-
ret = of_property_read_u32(node, "clock-frequency", &speed);
if (ret) {
dev_warn(dev, "No I2C speed selected, using 100kHz\n");
@@ -670,8 +641,7 @@ static int mxs_i2c_probe(struct platform_device *pdev)
struct pinctrl *pinctrl;
struct resource *res;
resource_size_t res_size;
- int err, irq, dmairq;
- dma_cap_mask_t mask;
+ int err, irq;
pinctrl = devm_pinctrl_get_select_default(dev);
if (IS_ERR(pinctrl))
@@ -683,9 +653,8 @@ static int mxs_i2c_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
- dmairq = platform_get_irq(pdev, 1);
- if (!res || irq < 0 || dmairq < 0)
+ if (!res || irq < 0)
return -ENOENT;
res_size = resource_size(res);
@@ -711,10 +680,7 @@ static int mxs_i2c_probe(struct platform_device *pdev)
}
/* Setup the DMA */
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- i2c->dma_data.chan_irq = dmairq;
- i2c->dmach = dma_request_channel(mask, mxs_i2c_dma_filter, i2c);
+ i2c->dmach = dma_request_slave_channel(dev, "rx-tx");
if (!i2c->dmach) {
dev_err(dev, "Failed to request dma\n");
return -ENODEV;
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index 146a53bfab71..4278a1787d08 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -552,22 +552,6 @@ static const struct mmc_host_ops mxs_mmc_ops = {
.enable_sdio_irq = mxs_mmc_enable_sdio_irq,
};
-static bool mxs_mmc_dma_filter(struct dma_chan *chan, void *param)
-{
- struct mxs_mmc_host *host = param;
- struct mxs_ssp *ssp = &host->ssp;
-
- if (!mxs_dma_is_apbh(chan))
- return false;
-
- if (chan->chan_id != ssp->dma_channel)
- return false;
-
- chan->private = &ssp->dma_data;
-
- return true;
-}
-
static struct platform_device_id mxs_ssp_ids[] = {
{
.name = "imx23-mmc",
@@ -595,20 +579,17 @@ static int mxs_mmc_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct mxs_mmc_host *host;
struct mmc_host *mmc;
- struct resource *iores, *dmares;
+ struct resource *iores;
struct pinctrl *pinctrl;
- int ret = 0, irq_err, irq_dma;
- dma_cap_mask_t mask;
+ int ret = 0, irq_err;
struct regulator *reg_vmmc;
enum of_gpio_flags flags;
struct mxs_ssp *ssp;
u32 bus_width = 0;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
irq_err = platform_get_irq(pdev, 0);
- irq_dma = platform_get_irq(pdev, 1);
- if (!iores || irq_err < 0 || irq_dma < 0)
+ if (!iores || irq_err < 0)
return -EINVAL;
mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev);
@@ -624,23 +605,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
goto out_mmc_free;
}
- if (np) {
- ssp->devid = (enum mxs_ssp_id) of_id->data;
- /*
- * TODO: This is a temporary solution and should be changed
- * to use generic DMA binding later when the helpers get in.
- */
- ret = of_property_read_u32(np, "fsl,ssp-dma-channel",
- &ssp->dma_channel);
- if (ret) {
- dev_err(mmc_dev(host->mmc),
- "failed to get dma channel\n");
- goto out_mmc_free;
- }
- } else {
- ssp->devid = pdev->id_entry->driver_data;
- ssp->dma_channel = dmares->start;
- }
+ ssp->devid = (enum mxs_ssp_id) of_id->data;
host->mmc = mmc;
host->sdio_irq_en = 0;
@@ -670,10 +635,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
mxs_mmc_reset(host);
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- ssp->dma_data.chan_irq = irq_dma;
- ssp->dmach = dma_request_channel(mask, mxs_mmc_dma_filter, host);
+ ssp->dmach = dma_request_slave_channel(&pdev->dev, "rx-tx");
if (!ssp->dmach) {
dev_err(mmc_dev(host->mmc),
"%s: failed to request dma\n", __func__);
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 717881a3d1b8..25ecfa1822a8 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -36,7 +36,6 @@
#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "gpmi-nand"
#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "bch"
#define GPMI_NAND_BCH_INTERRUPT_RES_NAME "bch"
-#define GPMI_NAND_DMA_INTERRUPT_RES_NAME "gpmi-dma"
/* add our owner bbt descriptor */
static uint8_t scan_ff_pattern[] = { 0xff };
@@ -420,28 +419,6 @@ static void release_bch_irq(struct gpmi_nand_data *this)
free_irq(i, this);
}
-static bool gpmi_dma_filter(struct dma_chan *chan, void *param)
-{
- struct gpmi_nand_data *this = param;
- int dma_channel = (int)this->private;
-
- if (!mxs_dma_is_apbh(chan))
- return false;
- /*
- * only catch the GPMI dma channels :
- * for mx23 : MX23_DMA_GPMI0 ~ MX23_DMA_GPMI3
- * (These four channels share the same IRQ!)
- *
- * for mx28 : MX28_DMA_GPMI0 ~ MX28_DMA_GPMI7
- * (These eight channels share the same IRQ!)
- */
- if (dma_channel == chan->chan_id) {
- chan->private = &this->dma_data;
- return true;
- }
- return false;
-}
-
static void release_dma_channels(struct gpmi_nand_data *this)
{
unsigned int i;
@@ -455,36 +432,10 @@ static void release_dma_channels(struct gpmi_nand_data *this)
static int acquire_dma_channels(struct gpmi_nand_data *this)
{
struct platform_device *pdev = this->pdev;
- struct resource *r_dma;
- struct device_node *dn;
- u32 dma_channel;
- int ret;
struct dma_chan *dma_chan;
- dma_cap_mask_t mask;
-
- /* dma channel, we only use the first one. */
- dn = pdev->dev.of_node;
- ret = of_property_read_u32(dn, "fsl,gpmi-dma-channel", &dma_channel);
- if (ret) {
- pr_err("unable to get DMA channel from dt.\n");
- goto acquire_err;
- }
- this->private = (void *)dma_channel;
-
- /* gpmi dma interrupt */
- r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
- GPMI_NAND_DMA_INTERRUPT_RES_NAME);
- if (!r_dma) {
- pr_err("Can't get resource for DMA\n");
- goto acquire_err;
- }
- this->dma_data.chan_irq = r_dma->start;
/* request dma channel */
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
-
- dma_chan = dma_request_channel(mask, gpmi_dma_filter, this);
+ dma_chan = dma_request_slave_channel(&pdev->dev, "rx-tx");
if (!dma_chan) {
pr_err("Failed to request DMA channel.\n");
goto acquire_err;
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
index 072947731277..a7685e3a8748 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
@@ -20,7 +20,7 @@
#include <linux/mtd/nand.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
-#include <linux/fsl/mxs-dma.h>
+#include <linux/dmaengine.h>
#define GPMI_CLK_MAX 5 /* MX6Q needs five clocks */
struct resources {
@@ -180,7 +180,6 @@ struct gpmi_nand_data {
/* DMA channels */
#define DMA_CHANS 8
struct dma_chan *dma_chans[DMA_CHANS];
- struct mxs_dma_data dma_data;
enum dma_ops_type last_dma_type;
enum dma_ops_type dma_type;
struct completion dma_done;
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index d44f65bac1d4..ceb4d43c132d 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -214,6 +214,7 @@ struct fec_enet_private {
struct clk *clk_ipg;
struct clk *clk_ahb;
+ struct clk *clk_enet_out;
struct clk *clk_ptp;
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index b9748f14ea78..e25bf832e6b3 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1883,18 +1883,23 @@ fec_probe(struct platform_device *pdev)
goto failed_clk;
}
+ /* enet_out is optional, depends on board */
+ fep->clk_enet_out = devm_clk_get(&pdev->dev, "enet_out");
+ if (IS_ERR(fep->clk_enet_out))
+ fep->clk_enet_out = NULL;
+
fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
fep->bufdesc_ex =
pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX;
if (IS_ERR(fep->clk_ptp)) {
- ret = PTR_ERR(fep->clk_ptp);
+ fep->clk_ptp = NULL;
fep->bufdesc_ex = 0;
}
clk_prepare_enable(fep->clk_ahb);
clk_prepare_enable(fep->clk_ipg);
- if (!IS_ERR(fep->clk_ptp))
- clk_prepare_enable(fep->clk_ptp);
+ clk_prepare_enable(fep->clk_enet_out);
+ clk_prepare_enable(fep->clk_ptp);
reg_phy = devm_regulator_get(&pdev->dev, "phy");
if (!IS_ERR(reg_phy)) {
@@ -1962,8 +1967,8 @@ failed_irq:
failed_regulator:
clk_disable_unprepare(fep->clk_ahb);
clk_disable_unprepare(fep->clk_ipg);
- if (!IS_ERR(fep->clk_ptp))
- clk_disable_unprepare(fep->clk_ptp);
+ clk_disable_unprepare(fep->clk_enet_out);
+ clk_disable_unprepare(fep->clk_ptp);
failed_pin:
failed_clk:
failed_ioremap:
@@ -1985,6 +1990,7 @@ fec_drv_remove(struct platform_device *pdev)
clk_disable_unprepare(fep->clk_ptp);
if (fep->ptp_clock)
ptp_clock_unregister(fep->ptp_clock);
+ clk_disable_unprepare(fep->clk_enet_out);
clk_disable_unprepare(fep->clk_ahb);
clk_disable_unprepare(fep->clk_ipg);
for (i = 0; i < FEC_IRQ_NUM; i++) {
@@ -2010,6 +2016,7 @@ fec_suspend(struct device *dev)
fec_stop(ndev);
netif_device_detach(ndev);
}
+ clk_disable_unprepare(fep->clk_enet_out);
clk_disable_unprepare(fep->clk_ahb);
clk_disable_unprepare(fep->clk_ipg);
@@ -2022,6 +2029,7 @@ fec_resume(struct device *dev)
struct net_device *ndev = dev_get_drvdata(dev);
struct fec_enet_private *fep = netdev_priv(ndev);
+ clk_prepare_enable(fep->clk_enet_out);
clk_prepare_enable(fep->clk_ahb);
clk_prepare_enable(fep->clk_ipg);
if (netif_running(ndev)) {
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index 8234d2259722..2e8f24a1fb95 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -776,10 +776,10 @@ rx_dma_failed:
#if defined(CONFIG_OF)
static const struct of_device_id davinci_spi_of_match[] = {
{
- .compatible = "ti,dm644x-spi",
+ .compatible = "ti,dm6441-spi",
},
{
- .compatible = "ti,da8xx-spi",
+ .compatible = "ti,da830-spi",
.data = (void *)SPI_VERSION_2,
},
{ },
diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
index a1d5778e2bbb..84982768cd10 100644
--- a/drivers/spi/spi-mxs.c
+++ b/drivers/spi/spi-mxs.c
@@ -490,21 +490,6 @@ static int mxs_spi_transfer_one(struct spi_master *master,
return status;
}
-static bool mxs_ssp_dma_filter(struct dma_chan *chan, void *param)
-{
- struct mxs_ssp *ssp = param;
-
- if (!mxs_dma_is_apbh(chan))
- return false;
-
- if (chan->chan_id != ssp->dma_channel)
- return false;
-
- chan->private = &ssp->dma_data;
-
- return true;
-}
-
static const struct of_device_id mxs_spi_dt_ids[] = {
{ .compatible = "fsl,imx23-spi", .data = (void *) IMX23_SSP, },
{ .compatible = "fsl,imx28-spi", .data = (void *) IMX28_SSP, },
@@ -520,13 +505,12 @@ static int mxs_spi_probe(struct platform_device *pdev)
struct spi_master *master;
struct mxs_spi *spi;
struct mxs_ssp *ssp;
- struct resource *iores, *dmares;
+ struct resource *iores;
struct pinctrl *pinctrl;
struct clk *clk;
void __iomem *base;
- int devid, dma_channel, clk_freq;
- int ret = 0, irq_err, irq_dma;
- dma_cap_mask_t mask;
+ int devid, clk_freq;
+ int ret = 0, irq_err;
/*
* Default clock speed for the SPI core. 160MHz seems to
@@ -537,8 +521,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq_err = platform_get_irq(pdev, 0);
- irq_dma = platform_get_irq(pdev, 1);
- if (!iores || irq_err < 0 || irq_dma < 0)
+ if (!iores || irq_err < 0)
return -EINVAL;
base = devm_ioremap_resource(&pdev->dev, iores);
@@ -553,32 +536,11 @@ static int mxs_spi_probe(struct platform_device *pdev)
if (IS_ERR(clk))
return PTR_ERR(clk);
- if (np) {
- devid = (enum mxs_ssp_id) of_id->data;
- /*
- * TODO: This is a temporary solution and should be changed
- * to use generic DMA binding later when the helpers get in.
- */
- ret = of_property_read_u32(np, "fsl,ssp-dma-channel",
- &dma_channel);
- if (ret) {
- dev_err(&pdev->dev,
- "Failed to get DMA channel\n");
- return -EINVAL;
- }
-
- ret = of_property_read_u32(np, "clock-frequency",
- &clk_freq);
- if (ret)
- clk_freq = clk_freq_default;
- } else {
- dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!dmares)
- return -EINVAL;
- devid = pdev->id_entry->driver_data;
- dma_channel = dmares->start;
+ devid = (enum mxs_ssp_id) of_id->data;
+ ret = of_property_read_u32(np, "clock-frequency",
+ &clk_freq);
+ if (ret)
clk_freq = clk_freq_default;
- }
master = spi_alloc_master(&pdev->dev, sizeof(*spi));
if (!master)
@@ -597,7 +559,6 @@ static int mxs_spi_probe(struct platform_device *pdev)
ssp->clk = clk;
ssp->base = base;
ssp->devid = devid;
- ssp->dma_channel = dma_channel;
init_completion(&spi->c);
@@ -606,10 +567,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
if (ret)
goto out_master_free;
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- ssp->dma_data.chan_irq = irq_dma;
- ssp->dmach = dma_request_channel(mask, mxs_ssp_dma_filter, ssp);
+ ssp->dmach = dma_request_slave_channel(&pdev->dev, "rx-tx");
if (!ssp->dmach) {
dev_err(ssp->dev, "Failed to request DMA\n");
ret = -ENODEV;
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 62e7d3b015a1..4f5f161896a1 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -35,7 +35,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/of_device.h>
#include <linux/dma-mapping.h>
-#include <linux/fsl/mxs-dma.h>
+#include <linux/dmaengine.h>
#include <asm/cacheflush.h>
@@ -148,11 +148,6 @@ struct mxs_auart_port {
struct device *dev;
/* for DMA */
- struct mxs_dma_data dma_data;
- int dma_channel_rx, dma_channel_tx;
- int dma_irq_rx, dma_irq_tx;
- int dma_channel;
-
struct scatterlist tx_sgl;
struct dma_chan *tx_dma_chan;
void *tx_dma_buf;
@@ -440,20 +435,6 @@ static u32 mxs_auart_get_mctrl(struct uart_port *u)
return mctrl;
}
-static bool mxs_auart_dma_filter(struct dma_chan *chan, void *param)
-{
- struct mxs_auart_port *s = param;
-
- if (!mxs_dma_is_apbx(chan))
- return false;
-
- if (s->dma_channel == chan->chan_id) {
- chan->private = &s->dma_data;
- return true;
- }
- return false;
-}
-
static int mxs_auart_dma_prep_rx(struct mxs_auart_port *s);
static void dma_rx_callback(void *arg)
{
@@ -545,21 +526,11 @@ static void mxs_auart_dma_exit(struct mxs_auart_port *s)
static int mxs_auart_dma_init(struct mxs_auart_port *s)
{
- dma_cap_mask_t mask;
-
if (auart_dma_enabled(s))
return 0;
- /* We do not get the right DMA channels. */
- if (s->dma_channel_rx == -1 || s->dma_channel_tx == -1)
- return -EINVAL;
-
/* init for RX */
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- s->dma_channel = s->dma_channel_rx;
- s->dma_data.chan_irq = s->dma_irq_rx;
- s->rx_dma_chan = dma_request_channel(mask, mxs_auart_dma_filter, s);
+ s->rx_dma_chan = dma_request_slave_channel(s->dev, "rx");
if (!s->rx_dma_chan)
goto err_out;
s->rx_dma_buf = kzalloc(UART_XMIT_SIZE, GFP_KERNEL | GFP_DMA);
@@ -567,9 +538,7 @@ static int mxs_auart_dma_init(struct mxs_auart_port *s)
goto err_out;
/* init for TX */
- s->dma_channel = s->dma_channel_tx;
- s->dma_data.chan_irq = s->dma_irq_tx;
- s->tx_dma_chan = dma_request_channel(mask, mxs_auart_dma_filter, s);
+ s->tx_dma_chan = dma_request_slave_channel(s->dev, "tx");
if (!s->tx_dma_chan)
goto err_out;
s->tx_dma_buf = kzalloc(UART_XMIT_SIZE, GFP_KERNEL | GFP_DMA);
@@ -1020,7 +989,6 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s,
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- u32 dma_channel[2];
int ret;
if (!np)
@@ -1034,20 +1002,8 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s,
}
s->port.line = ret;
- s->dma_irq_rx = platform_get_irq(pdev, 1);
- s->dma_irq_tx = platform_get_irq(pdev, 2);
+ s->flags |= MXS_AUART_DMA_CONFIG;
- ret = of_property_read_u32_array(np, "fsl,auart-dma-channel",
- dma_channel, 2);
- if (ret == 0) {
- s->dma_channel_rx = dma_channel[0];
- s->dma_channel_tx = dma_channel[1];
-
- s->flags |= MXS_AUART_DMA_CONFIG;
- } else {
- s->dma_channel_rx = -1;
- s->dma_channel_tx = -1;
- }
return 0;
}
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index ab5ba3d49e14..c04ccdf60eaa 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2428,6 +2428,8 @@ config FB_MXS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select FB_MODE_HELPERS
+ select OF_VIDEOMODE
help
Framebuffer support for the MXS SoC.
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 45169cbaba6e..1b2c26d1658c 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -42,13 +42,15 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
+#include <video/of_display_timing.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/pinctrl/consumer.h>
-#include <linux/mxsfb.h>
+#include <linux/fb.h>
+#include <linux/regulator/consumer.h>
+#include <video/videomode.h>
#define REG_SET 4
#define REG_CLR 8
@@ -107,7 +109,7 @@
#define VDCTRL0_ENABLE_PRESENT (1 << 28)
#define VDCTRL0_VSYNC_ACT_HIGH (1 << 27)
#define VDCTRL0_HSYNC_ACT_HIGH (1 << 26)
-#define VDCTRL0_DOTCLK_ACT_FAILING (1 << 25)
+#define VDCTRL0_DOTCLK_ACT_FALLING (1 << 25)
#define VDCTRL0_ENABLE_ACT_HIGH (1 << 24)
#define VDCTRL0_VSYNC_PERIOD_UNIT (1 << 21)
#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT (1 << 20)
@@ -142,6 +144,14 @@
#define BLUE 2
#define TRANSP 3
+#define STMLCDIF_8BIT 1 /** pixel data bus to the display is of 8 bit width */
+#define STMLCDIF_16BIT 0 /** pixel data bus to the display is of 16 bit width */
+#define STMLCDIF_18BIT 2 /** pixel data bus to the display is of 18 bit width */
+#define STMLCDIF_24BIT 3 /** pixel data bus to the display is of 24 bit width */
+
+#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT (1 << 6)
+#define MXSFB_SYNC_DOTCLK_FALLING_ACT (1 << 7) /* negtive edge sampling */
+
enum mxsfb_devtype {
MXSFB_V3,
MXSFB_V4,
@@ -168,8 +178,8 @@ struct mxsfb_info {
unsigned ld_intf_width;
unsigned dotclk_delay;
const struct mxsfb_devdata *devdata;
- int mapped;
u32 sync;
+ struct regulator *reg_lcd;
};
#define mxsfb_is_v3(host) (host->devdata->ipversion == 3)
@@ -329,9 +339,19 @@ static void mxsfb_enable_controller(struct fb_info *fb_info)
{
struct mxsfb_info *host = to_imxfb_host(fb_info);
u32 reg;
+ int ret;
dev_dbg(&host->pdev->dev, "%s\n", __func__);
+ if (host->reg_lcd) {
+ ret = regulator_enable(host->reg_lcd);
+ if (ret) {
+ dev_err(&host->pdev->dev,
+ "lcd regulator enable failed: %d\n", ret);
+ return;
+ }
+ }
+
clk_prepare_enable(host->clk);
clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U);
@@ -353,6 +373,7 @@ static void mxsfb_disable_controller(struct fb_info *fb_info)
struct mxsfb_info *host = to_imxfb_host(fb_info);
unsigned loop;
u32 reg;
+ int ret;
dev_dbg(&host->pdev->dev, "%s\n", __func__);
@@ -376,6 +397,13 @@ static void mxsfb_disable_controller(struct fb_info *fb_info)
clk_disable_unprepare(host->clk);
host->enabled = 0;
+
+ if (host->reg_lcd) {
+ ret = regulator_disable(host->reg_lcd);
+ if (ret)
+ dev_err(&host->pdev->dev,
+ "lcd regulator disable failed: %d\n", ret);
+ }
}
static int mxsfb_set_par(struct fb_info *fb_info)
@@ -459,8 +487,8 @@ static int mxsfb_set_par(struct fb_info *fb_info)
vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
if (host->sync & MXSFB_SYNC_DATA_ENABLE_HIGH_ACT)
vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
- if (host->sync & MXSFB_SYNC_DOTCLK_FAILING_ACT)
- vdctrl0 |= VDCTRL0_DOTCLK_ACT_FAILING;
+ if (host->sync & MXSFB_SYNC_DOTCLK_FALLING_ACT)
+ vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
writel(vdctrl0, host->base + LCDC_VDCTRL0);
@@ -679,14 +707,105 @@ static int mxsfb_restore_mode(struct mxsfb_info *host)
return 0;
}
+static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host)
+{
+ struct fb_info *fb_info = &host->fb_info;
+ struct fb_var_screeninfo *var = &fb_info->var;
+ struct device *dev = &host->pdev->dev;
+ struct device_node *np = host->pdev->dev.of_node;
+ struct device_node *display_np;
+ struct device_node *timings_np;
+ struct display_timings *timings;
+ u32 width;
+ int i;
+ int ret = 0;
+
+ display_np = of_parse_phandle(np, "display", 0);
+ if (!display_np) {
+ dev_err(dev, "failed to find display phandle\n");
+ return -ENOENT;
+ }
+
+ ret = of_property_read_u32(display_np, "bus-width", &width);
+ if (ret < 0) {
+ dev_err(dev, "failed to get property bus-width\n");
+ goto put_display_node;
+ }
+
+ switch (width) {
+ case 8:
+ host->ld_intf_width = STMLCDIF_8BIT;
+ break;
+ case 16:
+ host->ld_intf_width = STMLCDIF_16BIT;
+ break;
+ case 18:
+ host->ld_intf_width = STMLCDIF_18BIT;
+ break;
+ case 24:
+ host->ld_intf_width = STMLCDIF_24BIT;
+ break;
+ default:
+ dev_err(dev, "invalid bus-width value\n");
+ ret = -EINVAL;
+ goto put_display_node;
+ }
+
+ ret = of_property_read_u32(display_np, "bits-per-pixel",
+ &var->bits_per_pixel);
+ if (ret < 0) {
+ dev_err(dev, "failed to get property bits-per-pixel\n");
+ goto put_display_node;
+ }
+
+ timings = of_get_display_timings(display_np);
+ if (!timings) {
+ dev_err(dev, "failed to get display timings\n");
+ ret = -ENOENT;
+ goto put_display_node;
+ }
+
+ timings_np = of_find_node_by_name(display_np,
+ "display-timings");
+ if (!timings_np) {
+ dev_err(dev, "failed to find display-timings node\n");
+ ret = -ENOENT;
+ goto put_display_node;
+ }
+
+ for (i = 0; i < of_get_child_count(timings_np); i++) {
+ struct videomode vm;
+ struct fb_videomode fb_vm;
+
+ ret = videomode_from_timing(timings, &vm, i);
+ if (ret < 0)
+ goto put_timings_node;
+ ret = fb_videomode_from_videomode(&vm, &fb_vm);
+ if (ret < 0)
+ goto put_timings_node;
+
+ if (vm.data_flags & DISPLAY_FLAGS_DE_HIGH)
+ host->sync |= MXSFB_SYNC_DATA_ENABLE_HIGH_ACT;
+ if (vm.data_flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+ host->sync |= MXSFB_SYNC_DOTCLK_FALLING_ACT;
+ fb_add_videomode(&fb_vm, &fb_info->modelist);
+ }
+
+put_timings_node:
+ of_node_put(timings_np);
+put_display_node:
+ of_node_put(display_np);
+ return ret;
+}
+
static int mxsfb_init_fbinfo(struct mxsfb_info *host)
{
struct fb_info *fb_info = &host->fb_info;
struct fb_var_screeninfo *var = &fb_info->var;
- struct mxsfb_platform_data *pdata = host->pdev->dev.platform_data;
dma_addr_t fb_phys;
void *fb_virt;
- unsigned fb_size = pdata->fb_size;
+ unsigned fb_size;
+ int ret;
fb_info->fbops = &mxsfb_ops;
fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST;
@@ -696,40 +815,22 @@ static int mxsfb_init_fbinfo(struct mxsfb_info *host)
fb_info->fix.visual = FB_VISUAL_TRUECOLOR,
fb_info->fix.accel = FB_ACCEL_NONE;
- var->bits_per_pixel = pdata->default_bpp ? pdata->default_bpp : 16;
+ ret = mxsfb_init_fbinfo_dt(host);
+ if (ret)
+ return ret;
+
var->nonstd = 0;
var->activate = FB_ACTIVATE_NOW;
var->accel_flags = 0;
var->vmode = FB_VMODE_NONINTERLACED;
- host->dotclk_delay = pdata->dotclk_delay;
- host->ld_intf_width = pdata->ld_intf_width;
-
/* Memory allocation for framebuffer */
- if (pdata->fb_phys) {
- if (!fb_size)
- return -EINVAL;
-
- fb_phys = pdata->fb_phys;
-
- if (!request_mem_region(fb_phys, fb_size, host->pdev->name))
- return -ENOMEM;
+ fb_size = SZ_2M;
+ fb_virt = alloc_pages_exact(fb_size, GFP_DMA);
+ if (!fb_virt)
+ return -ENOMEM;
- fb_virt = ioremap(fb_phys, fb_size);
- if (!fb_virt) {
- release_mem_region(fb_phys, fb_size);
- return -ENOMEM;
- }
- host->mapped = 1;
- } else {
- if (!fb_size)
- fb_size = SZ_2M; /* default */
- fb_virt = alloc_pages_exact(fb_size, GFP_DMA);
- if (!fb_virt)
- return -ENOMEM;
-
- fb_phys = virt_to_phys(fb_virt);
- }
+ fb_phys = virt_to_phys(fb_virt);
fb_info->fix.smem_start = fb_phys;
fb_info->screen_base = fb_virt;
@@ -745,13 +846,7 @@ static void mxsfb_free_videomem(struct mxsfb_info *host)
{
struct fb_info *fb_info = &host->fb_info;
- if (host->mapped) {
- iounmap(fb_info->screen_base);
- release_mem_region(fb_info->fix.smem_start,
- fb_info->screen_size);
- } else {
- free_pages_exact(fb_info->screen_base, fb_info->fix.smem_len);
- }
+ free_pages_exact(fb_info->screen_base, fb_info->fix.smem_len);
}
static struct platform_device_id mxsfb_devtype[] = {
@@ -778,47 +873,35 @@ static int mxsfb_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(mxsfb_dt_ids, &pdev->dev);
- struct mxsfb_platform_data *pdata = pdev->dev.platform_data;
struct resource *res;
struct mxsfb_info *host;
struct fb_info *fb_info;
struct fb_modelist *modelist;
struct pinctrl *pinctrl;
- int panel_enable;
- enum of_gpio_flags flags;
- int i, ret;
+ int ret;
if (of_id)
pdev->id_entry = of_id->data;
- if (!pdata) {
- dev_err(&pdev->dev, "No platformdata. Giving up\n");
- return -ENODEV;
- }
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "Cannot get memory IO resource\n");
return -ENODEV;
}
- if (!request_mem_region(res->start, resource_size(res), pdev->name))
- return -EBUSY;
-
fb_info = framebuffer_alloc(sizeof(struct mxsfb_info), &pdev->dev);
if (!fb_info) {
dev_err(&pdev->dev, "Failed to allocate fbdev\n");
- ret = -ENOMEM;
- goto error_alloc_info;
+ return -ENOMEM;
}
host = to_imxfb_host(fb_info);
- host->base = ioremap(res->start, resource_size(res));
- if (!host->base) {
+ host->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(host->base)) {
dev_err(&pdev->dev, "ioremap failed\n");
- ret = -ENOMEM;
- goto error_ioremap;
+ ret = PTR_ERR(host->base);
+ goto fb_release;
}
host->pdev = pdev;
@@ -829,47 +912,31 @@ static int mxsfb_probe(struct platform_device *pdev)
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl)) {
ret = PTR_ERR(pinctrl);
- goto error_getpin;
+ goto fb_release;
}
- host->clk = clk_get(&host->pdev->dev, NULL);
+ host->clk = devm_clk_get(&host->pdev->dev, NULL);
if (IS_ERR(host->clk)) {
ret = PTR_ERR(host->clk);
- goto error_getclock;
+ goto fb_release;
}
- panel_enable = of_get_named_gpio_flags(pdev->dev.of_node,
- "panel-enable-gpios", 0, &flags);
- if (gpio_is_valid(panel_enable)) {
- unsigned long f = GPIOF_OUT_INIT_HIGH;
- if (flags == OF_GPIO_ACTIVE_LOW)
- f = GPIOF_OUT_INIT_LOW;
- ret = devm_gpio_request_one(&pdev->dev, panel_enable,
- f, "panel-enable");
- if (ret) {
- dev_err(&pdev->dev,
- "failed to request gpio %d: %d\n",
- panel_enable, ret);
- goto error_panel_enable;
- }
- }
+ host->reg_lcd = devm_regulator_get(&pdev->dev, "lcd");
+ if (IS_ERR(host->reg_lcd))
+ host->reg_lcd = NULL;
- fb_info->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+ fb_info->pseudo_palette = devm_kzalloc(&pdev->dev, sizeof(u32) * 16,
+ GFP_KERNEL);
if (!fb_info->pseudo_palette) {
ret = -ENOMEM;
- goto error_pseudo_pallette;
+ goto fb_release;
}
INIT_LIST_HEAD(&fb_info->modelist);
- host->sync = pdata->sync;
-
ret = mxsfb_init_fbinfo(host);
if (ret != 0)
- goto error_init_fb;
-
- for (i = 0; i < pdata->mode_count; i++)
- fb_add_videomode(&pdata->mode_list[i], &fb_info->modelist);
+ goto fb_release;
modelist = list_first_entry(&fb_info->modelist,
struct fb_modelist, list);
@@ -883,7 +950,7 @@ static int mxsfb_probe(struct platform_device *pdev)
ret = register_framebuffer(fb_info);
if (ret != 0) {
dev_err(&pdev->dev,"Failed to register framebuffer\n");
- goto error_register;
+ goto fb_destroy;
}
if (!host->enabled) {
@@ -896,22 +963,12 @@ static int mxsfb_probe(struct platform_device *pdev)
return 0;
-error_register:
+fb_destroy:
if (host->enabled)
clk_disable_unprepare(host->clk);
fb_destroy_modelist(&fb_info->modelist);
-error_init_fb:
- kfree(fb_info->pseudo_palette);
-error_pseudo_pallette:
-error_panel_enable:
- clk_put(host->clk);
-error_getclock:
-error_getpin:
- iounmap(host->base);
-error_ioremap:
+fb_release:
framebuffer_release(fb_info);
-error_alloc_info:
- release_mem_region(res->start, resource_size(res));
return ret;
}
@@ -920,19 +977,14 @@ static int mxsfb_remove(struct platform_device *pdev)
{
struct fb_info *fb_info = platform_get_drvdata(pdev);
struct mxsfb_info *host = to_imxfb_host(fb_info);
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (host->enabled)
mxsfb_disable_controller(fb_info);
unregister_framebuffer(fb_info);
- kfree(fb_info->pseudo_palette);
mxsfb_free_videomem(host);
- iounmap(host->base);
- clk_put(host->clk);
framebuffer_release(fb_info);
- release_mem_region(res->start, resource_size(res));
platform_set_drvdata(pdev, NULL);
OpenPOWER on IntegriCloud