Merge remote-tracking branches 'spi/topic/omap-100k', 'spi/topic/omap-uwire', 'spi/topic/pl022', 'spi/topic/pm' and 'spi/topic/pxa2xx' into spi-next
This commit is contained in:
commit
8afba181b9
|
@ -342,12 +342,11 @@ SPI protocol drivers somewhat resemble platform device drivers:
|
|||
.driver = {
|
||||
.name = "CHIP",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &CHIP_pm_ops,
|
||||
},
|
||||
|
||||
.probe = CHIP_probe,
|
||||
.remove = CHIP_remove,
|
||||
.suspend = CHIP_suspend,
|
||||
.resume = CHIP_resume,
|
||||
};
|
||||
|
||||
The driver core will automatically attempt to bind this driver to any SPI
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -294,16 +295,6 @@ static int omap1_spi100k_setup(struct spi_device *spi)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int omap1_spi100k_prepare_hardware(struct spi_master *master)
|
||||
{
|
||||
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
|
||||
|
||||
clk_prepare_enable(spi100k->ick);
|
||||
clk_prepare_enable(spi100k->fck);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap1_spi100k_transfer_one_message(struct spi_master *master,
|
||||
struct spi_message *m)
|
||||
{
|
||||
|
@ -372,16 +363,6 @@ static int omap1_spi100k_transfer_one_message(struct spi_master *master,
|
|||
return status;
|
||||
}
|
||||
|
||||
static int omap1_spi100k_unprepare_hardware(struct spi_master *master)
|
||||
{
|
||||
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
|
||||
|
||||
clk_disable_unprepare(spi100k->ick);
|
||||
clk_disable_unprepare(spi100k->fck);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap1_spi100k_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
|
@ -402,14 +383,12 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
|
|||
|
||||
master->setup = omap1_spi100k_setup;
|
||||
master->transfer_one_message = omap1_spi100k_transfer_one_message;
|
||||
master->prepare_transfer_hardware = omap1_spi100k_prepare_hardware;
|
||||
master->unprepare_transfer_hardware = omap1_spi100k_unprepare_hardware;
|
||||
master->cleanup = NULL;
|
||||
master->num_chipselect = 2;
|
||||
master->mode_bits = MODEBITS;
|
||||
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
|
||||
master->min_speed_hz = OMAP1_SPI100K_MAX_FREQ/(1<<16);
|
||||
master->max_speed_hz = OMAP1_SPI100K_MAX_FREQ;
|
||||
master->auto_runtime_pm = true;
|
||||
|
||||
spi100k = spi_master_get_devdata(master);
|
||||
|
||||
|
@ -434,22 +413,96 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
|
|||
goto err;
|
||||
}
|
||||
|
||||
status = clk_prepare_enable(spi100k->ick);
|
||||
if (status != 0) {
|
||||
dev_err(&pdev->dev, "failed to enable ick: %d\n", status);
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = clk_prepare_enable(spi100k->fck);
|
||||
if (status != 0) {
|
||||
dev_err(&pdev->dev, "failed to enable fck: %d\n", status);
|
||||
goto err_ick;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
|
||||
status = devm_spi_register_master(&pdev->dev, master);
|
||||
if (status < 0)
|
||||
goto err;
|
||||
goto err_fck;
|
||||
|
||||
return status;
|
||||
|
||||
err_fck:
|
||||
clk_disable_unprepare(spi100k->fck);
|
||||
err_ick:
|
||||
clk_disable_unprepare(spi100k->ick);
|
||||
err:
|
||||
spi_master_put(master);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int omap1_spi100k_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
|
||||
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
clk_disable_unprepare(spi100k->fck);
|
||||
clk_disable_unprepare(spi100k->ick);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int omap1_spi100k_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
|
||||
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
|
||||
|
||||
clk_disable_unprepare(spi100k->ick);
|
||||
clk_disable_unprepare(spi100k->fck);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap1_spi100k_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
|
||||
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(spi100k->ick);
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "Failed to enable ick: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(spi100k->fck);
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "Failed to enable fck: %d\n", ret);
|
||||
clk_disable_unprepare(spi100k->ick);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops omap1_spi100k_pm = {
|
||||
SET_RUNTIME_PM_OPS(omap1_spi100k_runtime_suspend,
|
||||
omap1_spi100k_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver omap1_spi100k_driver = {
|
||||
.driver = {
|
||||
.name = "omap1_spi100k",
|
||||
.pm = &omap1_spi100k_pm,
|
||||
},
|
||||
.probe = omap1_spi100k_probe,
|
||||
.remove = omap1_spi100k_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(omap1_spi100k_driver);
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
|
|
|
@ -285,7 +285,12 @@
|
|||
*/
|
||||
#define DEFAULT_SSP_REG_IMSC 0x0UL
|
||||
#define DISABLE_ALL_INTERRUPTS DEFAULT_SSP_REG_IMSC
|
||||
#define ENABLE_ALL_INTERRUPTS (~DEFAULT_SSP_REG_IMSC)
|
||||
#define ENABLE_ALL_INTERRUPTS ( \
|
||||
SSP_IMSC_MASK_RORIM | \
|
||||
SSP_IMSC_MASK_RTIM | \
|
||||
SSP_IMSC_MASK_RXIM | \
|
||||
SSP_IMSC_MASK_TXIM \
|
||||
)
|
||||
|
||||
#define CLEAR_ALL_INTERRUPTS 0x3
|
||||
|
||||
|
@ -1251,7 +1256,6 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
|
|||
struct pl022 *pl022 = dev_id;
|
||||
struct spi_message *msg = pl022->cur_msg;
|
||||
u16 irq_status = 0;
|
||||
u16 flag = 0;
|
||||
|
||||
if (unlikely(!msg)) {
|
||||
dev_err(&pl022->adev->dev,
|
||||
|
@ -1280,9 +1284,6 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
|
|||
if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RFF)
|
||||
dev_err(&pl022->adev->dev,
|
||||
"RXFIFO is full\n");
|
||||
if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_TNF)
|
||||
dev_err(&pl022->adev->dev,
|
||||
"TXFIFO is full\n");
|
||||
|
||||
/*
|
||||
* Disable and clear interrupts, disable SSP,
|
||||
|
@ -1303,8 +1304,7 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
|
|||
|
||||
readwriter(pl022);
|
||||
|
||||
if ((pl022->tx == pl022->tx_end) && (flag == 0)) {
|
||||
flag = 1;
|
||||
if (pl022->tx == pl022->tx_end) {
|
||||
/* Disable Transmit interrupt, enable receive interrupt */
|
||||
writew((readw(SSP_IMSC(pl022->virtbase)) &
|
||||
~SSP_IMSC_MASK_TXIM) | SSP_IMSC_MASK_RXIM,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/pxa2xx_spi.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
@ -30,10 +31,6 @@
|
|||
#include <linux/pm_runtime.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/delay.h>
|
||||
|
||||
#include "spi-pxa2xx.h"
|
||||
|
||||
MODULE_AUTHOR("Stephen Street");
|
||||
|
@ -67,54 +64,6 @@ MODULE_ALIAS("platform:pxa2xx-spi");
|
|||
#define LPSS_TX_LOTHRESH_DFLT 160
|
||||
#define LPSS_TX_HITHRESH_DFLT 224
|
||||
|
||||
struct quark_spi_rate {
|
||||
u32 bitrate;
|
||||
u32 dds_clk_rate;
|
||||
u32 clk_div;
|
||||
};
|
||||
|
||||
/*
|
||||
* 'rate', 'dds', 'clk_div' lookup table, which is defined in
|
||||
* the Quark SPI datasheet.
|
||||
*/
|
||||
static const struct quark_spi_rate quark_spi_rate_table[] = {
|
||||
/* bitrate, dds_clk_rate, clk_div */
|
||||
{50000000, 0x800000, 0},
|
||||
{40000000, 0x666666, 0},
|
||||
{25000000, 0x400000, 0},
|
||||
{20000000, 0x666666, 1},
|
||||
{16667000, 0x800000, 2},
|
||||
{13333000, 0x666666, 2},
|
||||
{12500000, 0x200000, 0},
|
||||
{10000000, 0x800000, 4},
|
||||
{8000000, 0x666666, 4},
|
||||
{6250000, 0x400000, 3},
|
||||
{5000000, 0x400000, 4},
|
||||
{4000000, 0x666666, 9},
|
||||
{3125000, 0x80000, 0},
|
||||
{2500000, 0x400000, 9},
|
||||
{2000000, 0x666666, 19},
|
||||
{1563000, 0x40000, 0},
|
||||
{1250000, 0x200000, 9},
|
||||
{1000000, 0x400000, 24},
|
||||
{800000, 0x666666, 49},
|
||||
{781250, 0x20000, 0},
|
||||
{625000, 0x200000, 19},
|
||||
{500000, 0x400000, 49},
|
||||
{400000, 0x666666, 99},
|
||||
{390625, 0x10000, 0},
|
||||
{250000, 0x400000, 99},
|
||||
{200000, 0x666666, 199},
|
||||
{195313, 0x8000, 0},
|
||||
{125000, 0x100000, 49},
|
||||
{100000, 0x200000, 124},
|
||||
{50000, 0x100000, 124},
|
||||
{25000, 0x80000, 124},
|
||||
{10016, 0x20000, 77},
|
||||
{5040, 0x20000, 154},
|
||||
{1002, 0x8000, 194},
|
||||
};
|
||||
|
||||
/* Offset from drv_data->lpss_base */
|
||||
#define GENERAL_REG 0x08
|
||||
#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
|
||||
|
@ -701,25 +650,124 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
/*
|
||||
* The Quark SPI data sheet gives a table, and for the given 'rate',
|
||||
* the 'dds' and 'clk_div' can be found in the table.
|
||||
* The Quark SPI has an additional 24 bit register (DDS_CLK_RATE) to multiply
|
||||
* input frequency by fractions of 2^24. It also has a divider by 5.
|
||||
*
|
||||
* There are formulas to get baud rate value for given input frequency and
|
||||
* divider parameters, such as DDS_CLK_RATE and SCR:
|
||||
*
|
||||
* Fsys = 200MHz
|
||||
*
|
||||
* Fssp = Fsys * DDS_CLK_RATE / 2^24 (1)
|
||||
* Baud rate = Fsclk = Fssp / (2 * (SCR + 1)) (2)
|
||||
*
|
||||
* DDS_CLK_RATE either 2^n or 2^n / 5.
|
||||
* SCR is in range 0 .. 255
|
||||
*
|
||||
* Divisor = 5^i * 2^j * 2 * k
|
||||
* i = [0, 1] i = 1 iff j = 0 or j > 3
|
||||
* j = [0, 23] j = 0 iff i = 1
|
||||
* k = [1, 256]
|
||||
* Special case: j = 0, i = 1: Divisor = 2 / 5
|
||||
*
|
||||
* Accordingly to the specification the recommended values for DDS_CLK_RATE
|
||||
* are:
|
||||
* Case 1: 2^n, n = [0, 23]
|
||||
* Case 2: 2^24 * 2 / 5 (0x666666)
|
||||
* Case 3: less than or equal to 2^24 / 5 / 16 (0x33333)
|
||||
*
|
||||
* In all cases the lowest possible value is better.
|
||||
*
|
||||
* The function calculates parameters for all cases and chooses the one closest
|
||||
* to the asked baud rate.
|
||||
*/
|
||||
static u32 quark_x1000_set_clk_regvals(u32 rate, u32 *dds, u32 *clk_div)
|
||||
static unsigned int quark_x1000_get_clk_div(int rate, u32 *dds)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned long xtal = 200000000;
|
||||
unsigned long fref = xtal / 2; /* mandatory division by 2,
|
||||
see (2) */
|
||||
/* case 3 */
|
||||
unsigned long fref1 = fref / 2; /* case 1 */
|
||||
unsigned long fref2 = fref * 2 / 5; /* case 2 */
|
||||
unsigned long scale;
|
||||
unsigned long q, q1, q2;
|
||||
long r, r1, r2;
|
||||
u32 mul;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(quark_spi_rate_table); i++) {
|
||||
if (rate >= quark_spi_rate_table[i].bitrate) {
|
||||
*dds = quark_spi_rate_table[i].dds_clk_rate;
|
||||
*clk_div = quark_spi_rate_table[i].clk_div;
|
||||
return quark_spi_rate_table[i].bitrate;
|
||||
/* Case 1 */
|
||||
|
||||
/* Set initial value for DDS_CLK_RATE */
|
||||
mul = (1 << 24) >> 1;
|
||||
|
||||
/* Calculate initial quot */
|
||||
q1 = DIV_ROUND_CLOSEST(fref1, rate);
|
||||
|
||||
/* Scale q1 if it's too big */
|
||||
if (q1 > 256) {
|
||||
/* Scale q1 to range [1, 512] */
|
||||
scale = fls_long(q1 - 1);
|
||||
if (scale > 9) {
|
||||
q1 >>= scale - 9;
|
||||
mul >>= scale - 9;
|
||||
}
|
||||
|
||||
/* Round the result if we have a remainder */
|
||||
q1 += q1 & 1;
|
||||
}
|
||||
|
||||
/* Decrease DDS_CLK_RATE as much as we can without loss in precision */
|
||||
scale = __ffs(q1);
|
||||
q1 >>= scale;
|
||||
mul >>= scale;
|
||||
|
||||
/* Get the remainder */
|
||||
r1 = abs(fref1 / (1 << (24 - fls_long(mul))) / q1 - rate);
|
||||
|
||||
/* Case 2 */
|
||||
|
||||
q2 = DIV_ROUND_CLOSEST(fref2, rate);
|
||||
r2 = abs(fref2 / q2 - rate);
|
||||
|
||||
/*
|
||||
* Choose the best between two: less remainder we have the better. We
|
||||
* can't go case 2 if q2 is greater than 256 since SCR register can
|
||||
* hold only values 0 .. 255.
|
||||
*/
|
||||
if (r2 >= r1 || q2 > 256) {
|
||||
/* case 1 is better */
|
||||
r = r1;
|
||||
q = q1;
|
||||
} else {
|
||||
/* case 2 is better */
|
||||
r = r2;
|
||||
q = q2;
|
||||
mul = (1 << 24) * 2 / 5;
|
||||
}
|
||||
|
||||
/* Check case 3 only If the divisor is big enough */
|
||||
if (fref / rate >= 80) {
|
||||
u64 fssp;
|
||||
u32 m;
|
||||
|
||||
/* Calculate initial quot */
|
||||
q1 = DIV_ROUND_CLOSEST(fref, rate);
|
||||
m = (1 << 24) / q1;
|
||||
|
||||
/* Get the remainder */
|
||||
fssp = (u64)fref * m;
|
||||
do_div(fssp, 1 << 24);
|
||||
r1 = abs(fssp - rate);
|
||||
|
||||
/* Choose this one if it suits better */
|
||||
if (r1 < r) {
|
||||
/* case 3 is better */
|
||||
q = 1;
|
||||
mul = m;
|
||||
}
|
||||
}
|
||||
|
||||
*dds = quark_spi_rate_table[i-1].dds_clk_rate;
|
||||
*clk_div = quark_spi_rate_table[i-1].clk_div;
|
||||
|
||||
return quark_spi_rate_table[i-1].bitrate;
|
||||
*dds = mul;
|
||||
return q - 1;
|
||||
}
|
||||
|
||||
static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate)
|
||||
|
@ -730,23 +778,25 @@ static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate)
|
|||
rate = min_t(int, ssp_clk, rate);
|
||||
|
||||
if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
|
||||
return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
|
||||
return (ssp_clk / (2 * rate) - 1) & 0xff;
|
||||
else
|
||||
return ((ssp_clk / rate - 1) & 0xfff) << 8;
|
||||
return (ssp_clk / rate - 1) & 0xfff;
|
||||
}
|
||||
|
||||
static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data,
|
||||
struct chip_data *chip, int rate)
|
||||
{
|
||||
u32 clk_div;
|
||||
unsigned int clk_div;
|
||||
|
||||
switch (drv_data->ssp_type) {
|
||||
case QUARK_X1000_SSP:
|
||||
quark_x1000_set_clk_regvals(rate, &chip->dds_rate, &clk_div);
|
||||
return clk_div << 8;
|
||||
clk_div = quark_x1000_get_clk_div(rate, &chip->dds_rate);
|
||||
break;
|
||||
default:
|
||||
return ssp_get_clk_div(drv_data, rate);
|
||||
clk_div = ssp_get_clk_div(drv_data, rate);
|
||||
break;
|
||||
}
|
||||
return clk_div << 8;
|
||||
}
|
||||
|
||||
static void pump_transfers(unsigned long data)
|
||||
|
|
|
@ -128,125 +128,11 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int spi_legacy_suspend(struct device *dev, pm_message_t message)
|
||||
{
|
||||
int value = 0;
|
||||
struct spi_driver *drv = to_spi_driver(dev->driver);
|
||||
|
||||
/* suspend will stop irqs and dma; no more i/o */
|
||||
if (drv) {
|
||||
if (drv->suspend)
|
||||
value = drv->suspend(to_spi_device(dev), message);
|
||||
else
|
||||
dev_dbg(dev, "... can't suspend\n");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static int spi_legacy_resume(struct device *dev)
|
||||
{
|
||||
int value = 0;
|
||||
struct spi_driver *drv = to_spi_driver(dev->driver);
|
||||
|
||||
/* resume may restart the i/o queue */
|
||||
if (drv) {
|
||||
if (drv->resume)
|
||||
value = drv->resume(to_spi_device(dev));
|
||||
else
|
||||
dev_dbg(dev, "... can't resume\n");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static int spi_pm_suspend(struct device *dev)
|
||||
{
|
||||
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
||||
|
||||
if (pm)
|
||||
return pm_generic_suspend(dev);
|
||||
else
|
||||
return spi_legacy_suspend(dev, PMSG_SUSPEND);
|
||||
}
|
||||
|
||||
static int spi_pm_resume(struct device *dev)
|
||||
{
|
||||
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
||||
|
||||
if (pm)
|
||||
return pm_generic_resume(dev);
|
||||
else
|
||||
return spi_legacy_resume(dev);
|
||||
}
|
||||
|
||||
static int spi_pm_freeze(struct device *dev)
|
||||
{
|
||||
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
||||
|
||||
if (pm)
|
||||
return pm_generic_freeze(dev);
|
||||
else
|
||||
return spi_legacy_suspend(dev, PMSG_FREEZE);
|
||||
}
|
||||
|
||||
static int spi_pm_thaw(struct device *dev)
|
||||
{
|
||||
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
||||
|
||||
if (pm)
|
||||
return pm_generic_thaw(dev);
|
||||
else
|
||||
return spi_legacy_resume(dev);
|
||||
}
|
||||
|
||||
static int spi_pm_poweroff(struct device *dev)
|
||||
{
|
||||
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
||||
|
||||
if (pm)
|
||||
return pm_generic_poweroff(dev);
|
||||
else
|
||||
return spi_legacy_suspend(dev, PMSG_HIBERNATE);
|
||||
}
|
||||
|
||||
static int spi_pm_restore(struct device *dev)
|
||||
{
|
||||
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
||||
|
||||
if (pm)
|
||||
return pm_generic_restore(dev);
|
||||
else
|
||||
return spi_legacy_resume(dev);
|
||||
}
|
||||
#else
|
||||
#define spi_pm_suspend NULL
|
||||
#define spi_pm_resume NULL
|
||||
#define spi_pm_freeze NULL
|
||||
#define spi_pm_thaw NULL
|
||||
#define spi_pm_poweroff NULL
|
||||
#define spi_pm_restore NULL
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops spi_pm = {
|
||||
.suspend = spi_pm_suspend,
|
||||
.resume = spi_pm_resume,
|
||||
.freeze = spi_pm_freeze,
|
||||
.thaw = spi_pm_thaw,
|
||||
.poweroff = spi_pm_poweroff,
|
||||
.restore = spi_pm_restore,
|
||||
SET_RUNTIME_PM_OPS(
|
||||
pm_generic_runtime_suspend,
|
||||
pm_generic_runtime_resume,
|
||||
NULL
|
||||
)
|
||||
};
|
||||
|
||||
struct bus_type spi_bus_type = {
|
||||
.name = "spi",
|
||||
.dev_groups = spi_dev_groups,
|
||||
.match = spi_match_device,
|
||||
.uevent = spi_uevent,
|
||||
.pm = &spi_pm,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(spi_bus_type);
|
||||
|
||||
|
|
|
@ -162,8 +162,6 @@ struct spi_transfer;
|
|||
* @remove: Unbinds this driver from the spi device
|
||||
* @shutdown: Standard shutdown callback used during system state
|
||||
* transitions such as powerdown/halt and kexec
|
||||
* @suspend: Standard suspend callback used during system state transitions
|
||||
* @resume: Standard resume callback used during system state transitions
|
||||
* @driver: SPI device drivers should initialize the name and owner
|
||||
* field of this structure.
|
||||
*
|
||||
|
@ -184,8 +182,6 @@ struct spi_driver {
|
|||
int (*probe)(struct spi_device *spi);
|
||||
int (*remove)(struct spi_device *spi);
|
||||
void (*shutdown)(struct spi_device *spi);
|
||||
int (*suspend)(struct spi_device *spi, pm_message_t mesg);
|
||||
int (*resume)(struct spi_device *spi);
|
||||
struct device_driver driver;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue