aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@st.com>2011-08-10 04:50:57 -0400
committerGrant Likely <grant.likely@secretlab.ca>2011-09-21 11:41:47 -0400
commit0379b2a33a8a03d4ad1036ef646419dbdf1ac15a (patch)
tree8b23e1c9779352c633f82d4d341222ab11df7593 /drivers/spi
parentb181565ee6a0f894bd6a134b9e5bed2966bdf9b3 (diff)
spi/spi-pl022: calculate_effective_freq() must set rate <= requested rate
There were few issues with calculate_effective_freq() routine: - It was returning first rate found >= requested rate. Now, if system have spi's rate as 83 MHz, with possible prescaled rates as 83, 41.5, 20.75, 13.83 (as we can prescale with multiples of 2). If user has given rate to be programmed as 22 MHz, then driver programmes it to 41.5 MHz. This looks to be incorrect, as user might have given the upper limit of the device, and we are programming it above it. - Driver finds the first satisfying rate and programmes it, but with other values of scr & cpsdvsr, it is possible to get more closer rate. This patch fixes these two issues, with some reformatting inside the code. This also creates a inline routine to calculate prescaled rate based on spi's rate, cpsdvsr and scr. Signed-off-by: Viresh Kumar <viresh.kumar@st.com> Tested-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/spi-pl022.c102
1 files changed, 51 insertions, 51 deletions
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index 248674c8a8c2..4e1a1e3b2a8c 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -1790,67 +1790,67 @@ static int pl022_transfer(struct spi_device *spi, struct spi_message *msg)
1790 return 0; 1790 return 0;
1791} 1791}
1792 1792
1793static int calculate_effective_freq(struct pl022 *pl022, 1793static inline u32 spi_rate(u32 rate, u16 cpsdvsr, u16 scr)
1794 int freq, 1794{
1795 struct ssp_clock_params *clk_freq) 1795 return rate / (cpsdvsr * (1 + scr));
1796}
1797
1798static int calculate_effective_freq(struct pl022 *pl022, int freq, struct
1799 ssp_clock_params * clk_freq)
1796{ 1800{
1797 /* Lets calculate the frequency parameters */ 1801 /* Lets calculate the frequency parameters */
1798 u16 cpsdvsr = 2; 1802 u16 cpsdvsr = CPSDVR_MIN, scr = SCR_MIN;
1799 u16 scr = 0; 1803 u32 rate, max_tclk, min_tclk, best_freq = 0, best_cpsdvsr = 0,
1800 bool freq_found = false; 1804 best_scr = 0, tmp, found = 0;
1801 u32 rate;
1802 u32 max_tclk;
1803 u32 min_tclk;
1804 1805
1805 rate = clk_get_rate(pl022->clk); 1806 rate = clk_get_rate(pl022->clk);
1806 /* cpsdvscr = 2 & scr 0 */ 1807 /* cpsdvscr = 2 & scr 0 */
1807 max_tclk = (rate / (CPSDVR_MIN * (1 + SCR_MIN))); 1808 max_tclk = spi_rate(rate, CPSDVR_MIN, SCR_MIN);
1808 /* cpsdvsr = 254 & scr = 255 */ 1809 /* cpsdvsr = 254 & scr = 255 */
1809 min_tclk = (rate / (CPSDVR_MAX * (1 + SCR_MAX))); 1810 min_tclk = spi_rate(rate, CPSDVR_MAX, SCR_MAX);
1810 1811
1811 if ((freq <= max_tclk) && (freq >= min_tclk)) { 1812 if (!((freq <= max_tclk) && (freq >= min_tclk))) {
1812 while (cpsdvsr <= CPSDVR_MAX && !freq_found) {
1813 while (scr <= SCR_MAX && !freq_found) {
1814 if ((rate /
1815 (cpsdvsr * (1 + scr))) > freq)
1816 scr += 1;
1817 else {
1818 /*
1819 * This bool is made true when
1820 * effective frequency >=
1821 * target frequency is found
1822 */
1823 freq_found = true;
1824 if ((rate /
1825 (cpsdvsr * (1 + scr))) != freq) {
1826 if (scr == SCR_MIN) {
1827 cpsdvsr -= 2;
1828 scr = SCR_MAX;
1829 } else
1830 scr -= 1;
1831 }
1832 }
1833 }
1834 if (!freq_found) {
1835 cpsdvsr += 2;
1836 scr = SCR_MIN;
1837 }
1838 }
1839 if (cpsdvsr != 0) {
1840 dev_dbg(&pl022->adev->dev,
1841 "SSP Effective Frequency is %u\n",
1842 (rate / (cpsdvsr * (1 + scr))));
1843 clk_freq->cpsdvsr = (u8) (cpsdvsr & 0xFF);
1844 clk_freq->scr = (u8) (scr & 0xFF);
1845 dev_dbg(&pl022->adev->dev,
1846 "SSP cpsdvsr = %d, scr = %d\n",
1847 clk_freq->cpsdvsr, clk_freq->scr);
1848 }
1849 } else {
1850 dev_err(&pl022->adev->dev, 1813 dev_err(&pl022->adev->dev,
1851 "controller data is incorrect: out of range frequency"); 1814 "controller data is incorrect: out of range frequency");
1852 return -EINVAL; 1815 return -EINVAL;
1853 } 1816 }
1817
1818 /*
1819 * best_freq will give closest possible available rate (<= requested
1820 * freq) for all values of scr & cpsdvsr.
1821 */
1822 while ((cpsdvsr <= CPSDVR_MAX) && !found) {
1823 while (scr <= SCR_MAX) {
1824 tmp = spi_rate(rate, cpsdvsr, scr);
1825
1826 if (tmp > freq)
1827 scr++;
1828 /*
1829 * If found exact value, update and break.
1830 * If found more closer value, update and continue.
1831 */
1832 else if ((tmp == freq) || (tmp > best_freq)) {
1833 best_freq = tmp;
1834 best_cpsdvsr = cpsdvsr;
1835 best_scr = scr;
1836
1837 if (tmp == freq)
1838 break;
1839 }
1840 scr++;
1841 }
1842 cpsdvsr += 2;
1843 scr = SCR_MIN;
1844 }
1845
1846 clk_freq->cpsdvsr = (u8) (best_cpsdvsr & 0xFF);
1847 clk_freq->scr = (u8) (best_scr & 0xFF);
1848 dev_dbg(&pl022->adev->dev,
1849 "SSP Target Frequency is: %u, Effective Frequency is %u\n",
1850 freq, best_freq);
1851 dev_dbg(&pl022->adev->dev, "SSP cpsdvsr = %d, scr = %d\n",
1852 clk_freq->cpsdvsr, clk_freq->scr);
1853
1854 return 0; 1854 return 0;
1855} 1855}
1856 1856