Loading Documentation/spi/spi-summary +1 −2 Original line number Diff line number Diff line Loading @@ -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 Loading drivers/spi/spi-omap-100k.c +77 −24 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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); Loading @@ -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); Loading drivers/spi/spi-omap-uwire.c +0 −1 Original line number Diff line number Diff line Loading @@ -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> Loading drivers/spi/spi-pl022.c +7 −7 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading Loading @@ -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, Loading @@ -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, Loading drivers/spi/spi-pxa2xx.c +121 −71 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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"); Loading Loading @@ -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) Loading Loading @@ -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; /* 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; } 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; /* 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; } *dds = quark_spi_rate_table[i-1].dds_clk_rate; *clk_div = quark_spi_rate_table[i-1].clk_div; /* 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; return quark_spi_rate_table[i-1].bitrate; /* 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 = mul; return q - 1; } static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate) Loading @@ -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) Loading Loading
Documentation/spi/spi-summary +1 −2 Original line number Diff line number Diff line Loading @@ -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 Loading
drivers/spi/spi-omap-100k.c +77 −24 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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); Loading @@ -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); Loading
drivers/spi/spi-omap-uwire.c +0 −1 Original line number Diff line number Diff line Loading @@ -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> Loading
drivers/spi/spi-pl022.c +7 −7 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading Loading @@ -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, Loading @@ -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, Loading
drivers/spi/spi-pxa2xx.c +121 −71 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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"); Loading Loading @@ -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) Loading Loading @@ -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; /* 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; } 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; /* 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; } *dds = quark_spi_rate_table[i-1].dds_clk_rate; *clk_div = quark_spi_rate_table[i-1].clk_div; /* 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; return quark_spi_rate_table[i-1].bitrate; /* 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 = mul; return q - 1; } static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate) Loading @@ -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) Loading