aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/spi/spi-clps711x.c86
1 files changed, 57 insertions, 29 deletions
diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c
index ab010c05dc5a..d9eec4e3b246 100644
--- a/drivers/spi/spi-clps711x.c
+++ b/drivers/spi/spi-clps711x.c
@@ -17,14 +17,21 @@
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/interrupt.h> 18#include <linux/interrupt.h>
19#include <linux/platform_device.h> 19#include <linux/platform_device.h>
20#include <linux/regmap.h>
21#include <linux/mfd/syscon.h>
22#include <linux/mfd/syscon/clps711x.h>
20#include <linux/spi/spi.h> 23#include <linux/spi/spi.h>
21#include <linux/platform_data/spi-clps711x.h> 24#include <linux/platform_data/spi-clps711x.h>
22 25
23#include <mach/hardware.h>
24
25#define DRIVER_NAME "spi-clps711x" 26#define DRIVER_NAME "spi-clps711x"
26 27
28#define SYNCIO_FRMLEN(x) ((x) << 8)
29#define SYNCIO_TXFRMEN (1 << 14)
30
27struct spi_clps711x_data { 31struct spi_clps711x_data {
32 void __iomem *syncio;
33 struct regmap *syscon;
34 struct regmap *syscon1;
28 struct clk *spi_clk; 35 struct clk *spi_clk;
29 u32 max_speed_hz; 36 u32 max_speed_hz;
30 37
@@ -49,31 +56,29 @@ static void spi_clps711x_setup_xfer(struct spi_device *spi,
49 56
50 /* Setup SPI frequency divider */ 57 /* Setup SPI frequency divider */
51 if (!xfer->speed_hz || (xfer->speed_hz >= hw->max_speed_hz)) 58 if (!xfer->speed_hz || (xfer->speed_hz >= hw->max_speed_hz))
52 clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | 59 regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
53 SYSCON1_ADCKSEL(3), SYSCON1); 60 SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(3));
54 else if (xfer->speed_hz >= (hw->max_speed_hz / 2)) 61 else if (xfer->speed_hz >= (hw->max_speed_hz / 2))
55 clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | 62 regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
56 SYSCON1_ADCKSEL(2), SYSCON1); 63 SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(2));
57 else if (xfer->speed_hz >= (hw->max_speed_hz / 8)) 64 else if (xfer->speed_hz >= (hw->max_speed_hz / 8))
58 clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | 65 regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
59 SYSCON1_ADCKSEL(1), SYSCON1); 66 SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(1));
60 else 67 else
61 clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | 68 regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
62 SYSCON1_ADCKSEL(0), SYSCON1); 69 SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(0));
63} 70}
64 71
65static int spi_clps711x_prepare_message(struct spi_master *master, 72static int spi_clps711x_prepare_message(struct spi_master *master,
66 struct spi_message *msg) 73 struct spi_message *msg)
67{ 74{
75 struct spi_clps711x_data *hw = spi_master_get_devdata(master);
68 struct spi_device *spi = msg->spi; 76 struct spi_device *spi = msg->spi;
69 77
70 /* Setup edge for transfer */ 78 /* Setup mode for transfer */
71 if (spi->mode & SPI_CPHA) 79 return regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCKNSEN,
72 clps_writew(clps_readw(SYSCON3) | SYSCON3_ADCCKNSEN, SYSCON3); 80 (spi->mode & SPI_CPHA) ?
73 else 81 SYSCON3_ADCCKNSEN : 0);
74 clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCKNSEN, SYSCON3);
75
76 return 0;
77} 82}
78 83
79static int spi_clps711x_transfer_one(struct spi_master *master, 84static int spi_clps711x_transfer_one(struct spi_master *master,
@@ -92,7 +97,8 @@ static int spi_clps711x_transfer_one(struct spi_master *master,
92 97
93 /* Initiate transfer */ 98 /* Initiate transfer */
94 data = hw->tx_buf ? *hw->tx_buf++ : 0; 99 data = hw->tx_buf ? *hw->tx_buf++ : 0;
95 clps_writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, SYNCIO); 100 writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, hw->syncio);
101
96 return 1; 102 return 1;
97} 103}
98 104
@@ -103,15 +109,15 @@ static irqreturn_t spi_clps711x_isr(int irq, void *dev_id)
103 u8 data; 109 u8 data;
104 110
105 /* Handle RX */ 111 /* Handle RX */
106 data = clps_readb(SYNCIO); 112 data = readb(hw->syncio);
107 if (hw->rx_buf) 113 if (hw->rx_buf)
108 *hw->rx_buf++ = data; 114 *hw->rx_buf++ = data;
109 115
110 /* Handle TX */ 116 /* Handle TX */
111 if (--hw->len > 0) { 117 if (--hw->len > 0) {
112 data = hw->tx_buf ? *hw->tx_buf++ : 0; 118 data = hw->tx_buf ? *hw->tx_buf++ : 0;
113 clps_writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, 119 writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN,
114 SYNCIO); 120 hw->syncio);
115 } else 121 } else
116 spi_finalize_current_transfer(master); 122 spi_finalize_current_transfer(master);
117 123
@@ -120,10 +126,11 @@ static irqreturn_t spi_clps711x_isr(int irq, void *dev_id)
120 126
121static int spi_clps711x_probe(struct platform_device *pdev) 127static int spi_clps711x_probe(struct platform_device *pdev)
122{ 128{
123 int i, ret;
124 struct spi_master *master;
125 struct spi_clps711x_data *hw; 129 struct spi_clps711x_data *hw;
126 struct spi_clps711x_pdata *pdata = dev_get_platdata(&pdev->dev); 130 struct spi_clps711x_pdata *pdata = dev_get_platdata(&pdev->dev);
131 struct spi_master *master;
132 struct resource *res;
133 int i, irq, ret;
127 134
128 if (!pdata) { 135 if (!pdata) {
129 dev_err(&pdev->dev, "No platform data supplied\n"); 136 dev_err(&pdev->dev, "No platform data supplied\n");
@@ -135,6 +142,10 @@ static int spi_clps711x_probe(struct platform_device *pdev)
135 return -EINVAL; 142 return -EINVAL;
136 } 143 }
137 144
145 irq = platform_get_irq(pdev, 0);
146 if (irq < 0)
147 return irq;
148
138 master = spi_alloc_master(&pdev->dev, sizeof(*hw)); 149 master = spi_alloc_master(&pdev->dev, sizeof(*hw));
139 if (!master) 150 if (!master)
140 return -ENOMEM; 151 return -ENOMEM;
@@ -176,18 +187,35 @@ static int spi_clps711x_probe(struct platform_device *pdev)
176 187
177 platform_set_drvdata(pdev, master); 188 platform_set_drvdata(pdev, master);
178 189
190 hw->syscon = syscon_regmap_lookup_by_pdevname("syscon.3");
191 if (IS_ERR(hw->syscon)) {
192 ret = PTR_ERR(hw->syscon);
193 goto err_out;
194 }
195
196 hw->syscon1 = syscon_regmap_lookup_by_pdevname("syscon.1");
197 if (IS_ERR(hw->syscon1)) {
198 ret = PTR_ERR(hw->syscon1);
199 goto err_out;
200 }
201
202 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
203 hw->syncio = devm_ioremap_resource(&pdev->dev, res);
204 if (IS_ERR(hw->syncio)) {
205 ret = PTR_ERR(hw->syncio);
206 goto err_out;
207 }
208
179 /* Disable extended mode due hardware problems */ 209 /* Disable extended mode due hardware problems */
180 clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCON, SYSCON3); 210 regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCON, 0);
181 211
182 /* Clear possible pending interrupt */ 212 /* Clear possible pending interrupt */
183 clps_readl(SYNCIO); 213 readl(hw->syncio);
184 214
185 ret = devm_request_irq(&pdev->dev, IRQ_SSEOTI, spi_clps711x_isr, 0, 215 ret = devm_request_irq(&pdev->dev, irq, spi_clps711x_isr, 0,
186 dev_name(&pdev->dev), master); 216 dev_name(&pdev->dev), master);
187 if (ret) { 217 if (ret)
188 dev_err(&pdev->dev, "Can't request IRQ\n");
189 goto err_out; 218 goto err_out;
190 }
191 219
192 ret = devm_spi_register_master(&pdev->dev, master); 220 ret = devm_spi_register_master(&pdev->dev, master);
193 if (!ret) { 221 if (!ret) {