| .. | .. |
|---|
| 9 | 9 | |
|---|
| 10 | 10 | #include <linux/bitfield.h> |
|---|
| 11 | 11 | #include <linux/clk.h> |
|---|
| 12 | +#include <linux/clk-provider.h> |
|---|
| 12 | 13 | #include <linux/device.h> |
|---|
| 13 | 14 | #include <linux/io.h> |
|---|
| 14 | 15 | #include <linux/kernel.h> |
|---|
| 15 | 16 | #include <linux/module.h> |
|---|
| 16 | 17 | #include <linux/of.h> |
|---|
| 18 | +#include <linux/of_device.h> |
|---|
| 17 | 19 | #include <linux/platform_device.h> |
|---|
| 18 | 20 | #include <linux/spi/spi.h> |
|---|
| 19 | 21 | #include <linux/types.h> |
|---|
| 20 | 22 | #include <linux/interrupt.h> |
|---|
| 21 | 23 | #include <linux/reset.h> |
|---|
| 22 | | -#include <linux/gpio.h> |
|---|
| 23 | 24 | |
|---|
| 24 | 25 | /* |
|---|
| 25 | 26 | * The Meson SPICC controller could support DMA based transfers, but is not |
|---|
| .. | .. |
|---|
| 34 | 35 | * to have a CS go down over the full transfer |
|---|
| 35 | 36 | */ |
|---|
| 36 | 37 | |
|---|
| 37 | | -#define SPICC_MAX_FREQ 30000000 |
|---|
| 38 | 38 | #define SPICC_MAX_BURST 128 |
|---|
| 39 | 39 | |
|---|
| 40 | 40 | /* Register Map */ |
|---|
| .. | .. |
|---|
| 106 | 106 | #define SPICC_SWAP_RO BIT(14) /* RX FIFO Data Swap Read-Only */ |
|---|
| 107 | 107 | #define SPICC_SWAP_W1 BIT(15) /* RX FIFO Data Swap Write-Only */ |
|---|
| 108 | 108 | #define SPICC_DLYCTL_RO_MASK GENMASK(20, 15) /* Delay Control Read-Only */ |
|---|
| 109 | | -#define SPICC_DLYCTL_W1_MASK GENMASK(21, 16) /* Delay Control Write-Only */ |
|---|
| 109 | +#define SPICC_MO_DELAY_MASK GENMASK(17, 16) /* Master Output Delay */ |
|---|
| 110 | +#define SPICC_MO_NO_DELAY 0 |
|---|
| 111 | +#define SPICC_MO_DELAY_1_CYCLE 1 |
|---|
| 112 | +#define SPICC_MO_DELAY_2_CYCLE 2 |
|---|
| 113 | +#define SPICC_MO_DELAY_3_CYCLE 3 |
|---|
| 114 | +#define SPICC_MI_DELAY_MASK GENMASK(19, 18) /* Master Input Delay */ |
|---|
| 115 | +#define SPICC_MI_NO_DELAY 0 |
|---|
| 116 | +#define SPICC_MI_DELAY_1_CYCLE 1 |
|---|
| 117 | +#define SPICC_MI_DELAY_2_CYCLE 2 |
|---|
| 118 | +#define SPICC_MI_DELAY_3_CYCLE 3 |
|---|
| 119 | +#define SPICC_MI_CAP_DELAY_MASK GENMASK(21, 20) /* Master Capture Delay */ |
|---|
| 120 | +#define SPICC_CAP_AHEAD_2_CYCLE 0 |
|---|
| 121 | +#define SPICC_CAP_AHEAD_1_CYCLE 1 |
|---|
| 122 | +#define SPICC_CAP_NO_DELAY 2 |
|---|
| 123 | +#define SPICC_CAP_DELAY_1_CYCLE 3 |
|---|
| 110 | 124 | #define SPICC_FIFORST_RO_MASK GENMASK(22, 21) /* FIFO Softreset Read-Only */ |
|---|
| 111 | 125 | #define SPICC_FIFORST_W1_MASK GENMASK(23, 22) /* FIFO Softreset Write-Only */ |
|---|
| 112 | 126 | |
|---|
| .. | .. |
|---|
| 114 | 128 | |
|---|
| 115 | 129 | #define SPICC_DWADDR 0x24 /* Write Address of DMA */ |
|---|
| 116 | 130 | |
|---|
| 131 | +#define SPICC_ENH_CTL0 0x38 /* Enhanced Feature */ |
|---|
| 132 | +#define SPICC_ENH_CLK_CS_DELAY_MASK GENMASK(15, 0) |
|---|
| 133 | +#define SPICC_ENH_DATARATE_MASK GENMASK(23, 16) |
|---|
| 134 | +#define SPICC_ENH_DATARATE_EN BIT(24) |
|---|
| 135 | +#define SPICC_ENH_MOSI_OEN BIT(25) |
|---|
| 136 | +#define SPICC_ENH_CLK_OEN BIT(26) |
|---|
| 137 | +#define SPICC_ENH_CS_OEN BIT(27) |
|---|
| 138 | +#define SPICC_ENH_CLK_CS_DELAY_EN BIT(28) |
|---|
| 139 | +#define SPICC_ENH_MAIN_CLK_AO BIT(29) |
|---|
| 140 | + |
|---|
| 117 | 141 | #define writel_bits_relaxed(mask, val, addr) \ |
|---|
| 118 | 142 | writel_relaxed((readl_relaxed(addr) & ~(mask)) | (val), addr) |
|---|
| 119 | 143 | |
|---|
| 120 | | -#define SPICC_BURST_MAX 16 |
|---|
| 121 | | -#define SPICC_FIFO_HALF 10 |
|---|
| 144 | +struct meson_spicc_data { |
|---|
| 145 | + unsigned int max_speed_hz; |
|---|
| 146 | + unsigned int min_speed_hz; |
|---|
| 147 | + unsigned int fifo_size; |
|---|
| 148 | + bool has_oen; |
|---|
| 149 | + bool has_enhance_clk_div; |
|---|
| 150 | + bool has_pclk; |
|---|
| 151 | +}; |
|---|
| 122 | 152 | |
|---|
| 123 | 153 | struct meson_spicc_device { |
|---|
| 124 | 154 | struct spi_master *master; |
|---|
| 125 | 155 | struct platform_device *pdev; |
|---|
| 126 | 156 | void __iomem *base; |
|---|
| 127 | 157 | struct clk *core; |
|---|
| 158 | + struct clk *pclk; |
|---|
| 159 | + struct clk_divider pow2_div; |
|---|
| 160 | + struct clk *clk; |
|---|
| 128 | 161 | struct spi_message *message; |
|---|
| 129 | 162 | struct spi_transfer *xfer; |
|---|
| 163 | + const struct meson_spicc_data *data; |
|---|
| 130 | 164 | u8 *tx_buf; |
|---|
| 131 | 165 | u8 *rx_buf; |
|---|
| 132 | 166 | unsigned int bytes_per_word; |
|---|
| 133 | 167 | unsigned long tx_remain; |
|---|
| 134 | | - unsigned long txb_remain; |
|---|
| 135 | 168 | unsigned long rx_remain; |
|---|
| 136 | | - unsigned long rxb_remain; |
|---|
| 137 | 169 | unsigned long xfer_remain; |
|---|
| 138 | | - bool is_burst_end; |
|---|
| 139 | | - bool is_last_burst; |
|---|
| 140 | 170 | }; |
|---|
| 171 | + |
|---|
| 172 | +#define pow2_clk_to_spicc(_div) container_of(_div, struct meson_spicc_device, pow2_div) |
|---|
| 173 | + |
|---|
| 174 | +static void meson_spicc_oen_enable(struct meson_spicc_device *spicc) |
|---|
| 175 | +{ |
|---|
| 176 | + u32 conf; |
|---|
| 177 | + |
|---|
| 178 | + if (!spicc->data->has_oen) |
|---|
| 179 | + return; |
|---|
| 180 | + |
|---|
| 181 | + conf = readl_relaxed(spicc->base + SPICC_ENH_CTL0) | |
|---|
| 182 | + SPICC_ENH_MOSI_OEN | SPICC_ENH_CLK_OEN | SPICC_ENH_CS_OEN; |
|---|
| 183 | + |
|---|
| 184 | + writel_relaxed(conf, spicc->base + SPICC_ENH_CTL0); |
|---|
| 185 | +} |
|---|
| 141 | 186 | |
|---|
| 142 | 187 | static inline bool meson_spicc_txfull(struct meson_spicc_device *spicc) |
|---|
| 143 | 188 | { |
|---|
| .. | .. |
|---|
| 147 | 192 | |
|---|
| 148 | 193 | static inline bool meson_spicc_rxready(struct meson_spicc_device *spicc) |
|---|
| 149 | 194 | { |
|---|
| 150 | | - return FIELD_GET(SPICC_RH | SPICC_RR | SPICC_RF_EN, |
|---|
| 195 | + return FIELD_GET(SPICC_RH | SPICC_RR | SPICC_RF, |
|---|
| 151 | 196 | readl_relaxed(spicc->base + SPICC_STATREG)); |
|---|
| 152 | 197 | } |
|---|
| 153 | 198 | |
|---|
| .. | .. |
|---|
| 202 | 247 | spicc->base + SPICC_TXDATA); |
|---|
| 203 | 248 | } |
|---|
| 204 | 249 | |
|---|
| 205 | | -static inline u32 meson_spicc_setup_rx_irq(struct meson_spicc_device *spicc, |
|---|
| 206 | | - u32 irq_ctrl) |
|---|
| 250 | +static inline void meson_spicc_setup_burst(struct meson_spicc_device *spicc) |
|---|
| 207 | 251 | { |
|---|
| 208 | | - if (spicc->rx_remain > SPICC_FIFO_HALF) |
|---|
| 209 | | - irq_ctrl |= SPICC_RH_EN; |
|---|
| 210 | | - else |
|---|
| 211 | | - irq_ctrl |= SPICC_RR_EN; |
|---|
| 212 | 252 | |
|---|
| 213 | | - return irq_ctrl; |
|---|
| 214 | | -} |
|---|
| 215 | | - |
|---|
| 216 | | -static inline void meson_spicc_setup_burst(struct meson_spicc_device *spicc, |
|---|
| 217 | | - unsigned int burst_len) |
|---|
| 218 | | -{ |
|---|
| 253 | + unsigned int burst_len = min_t(unsigned int, |
|---|
| 254 | + spicc->xfer_remain / |
|---|
| 255 | + spicc->bytes_per_word, |
|---|
| 256 | + spicc->data->fifo_size); |
|---|
| 219 | 257 | /* Setup Xfer variables */ |
|---|
| 220 | 258 | spicc->tx_remain = burst_len; |
|---|
| 221 | 259 | spicc->rx_remain = burst_len; |
|---|
| 222 | 260 | spicc->xfer_remain -= burst_len * spicc->bytes_per_word; |
|---|
| 223 | | - spicc->is_burst_end = false; |
|---|
| 224 | | - if (burst_len < SPICC_BURST_MAX || !spicc->xfer_remain) |
|---|
| 225 | | - spicc->is_last_burst = true; |
|---|
| 226 | | - else |
|---|
| 227 | | - spicc->is_last_burst = false; |
|---|
| 228 | 261 | |
|---|
| 229 | 262 | /* Setup burst length */ |
|---|
| 230 | 263 | writel_bits_relaxed(SPICC_BURSTLENGTH_MASK, |
|---|
| 231 | 264 | FIELD_PREP(SPICC_BURSTLENGTH_MASK, |
|---|
| 232 | | - burst_len), |
|---|
| 265 | + burst_len - 1), |
|---|
| 233 | 266 | spicc->base + SPICC_CONREG); |
|---|
| 234 | 267 | |
|---|
| 235 | 268 | /* Fill TX FIFO */ |
|---|
| .. | .. |
|---|
| 239 | 272 | static irqreturn_t meson_spicc_irq(int irq, void *data) |
|---|
| 240 | 273 | { |
|---|
| 241 | 274 | struct meson_spicc_device *spicc = (void *) data; |
|---|
| 242 | | - u32 ctrl = readl_relaxed(spicc->base + SPICC_INTREG); |
|---|
| 243 | | - u32 stat = readl_relaxed(spicc->base + SPICC_STATREG) & ctrl; |
|---|
| 244 | 275 | |
|---|
| 245 | | - ctrl &= ~(SPICC_RH_EN | SPICC_RR_EN); |
|---|
| 276 | + writel_bits_relaxed(SPICC_TC, SPICC_TC, spicc->base + SPICC_STATREG); |
|---|
| 246 | 277 | |
|---|
| 247 | 278 | /* Empty RX FIFO */ |
|---|
| 248 | 279 | meson_spicc_rx(spicc); |
|---|
| 249 | 280 | |
|---|
| 250 | | - /* Enable TC interrupt since we transferred everything */ |
|---|
| 251 | | - if (!spicc->tx_remain && !spicc->rx_remain) { |
|---|
| 252 | | - spicc->is_burst_end = true; |
|---|
| 281 | + if (!spicc->xfer_remain) { |
|---|
| 282 | + /* Disable all IRQs */ |
|---|
| 283 | + writel(0, spicc->base + SPICC_INTREG); |
|---|
| 253 | 284 | |
|---|
| 254 | | - /* Enable TC interrupt */ |
|---|
| 255 | | - ctrl |= SPICC_TC_EN; |
|---|
| 285 | + spi_finalize_current_transfer(spicc->master); |
|---|
| 256 | 286 | |
|---|
| 257 | | - /* Reload IRQ status */ |
|---|
| 258 | | - stat = readl_relaxed(spicc->base + SPICC_STATREG) & ctrl; |
|---|
| 287 | + return IRQ_HANDLED; |
|---|
| 259 | 288 | } |
|---|
| 260 | 289 | |
|---|
| 261 | | - /* Check transfer complete */ |
|---|
| 262 | | - if ((stat & SPICC_TC) && spicc->is_burst_end) { |
|---|
| 263 | | - unsigned int burst_len; |
|---|
| 290 | + /* Setup burst */ |
|---|
| 291 | + meson_spicc_setup_burst(spicc); |
|---|
| 264 | 292 | |
|---|
| 265 | | - /* Clear TC bit */ |
|---|
| 266 | | - writel_relaxed(SPICC_TC, spicc->base + SPICC_STATREG); |
|---|
| 267 | | - |
|---|
| 268 | | - /* Disable TC interrupt */ |
|---|
| 269 | | - ctrl &= ~SPICC_TC_EN; |
|---|
| 270 | | - |
|---|
| 271 | | - if (spicc->is_last_burst) { |
|---|
| 272 | | - /* Disable all IRQs */ |
|---|
| 273 | | - writel(0, spicc->base + SPICC_INTREG); |
|---|
| 274 | | - |
|---|
| 275 | | - spi_finalize_current_transfer(spicc->master); |
|---|
| 276 | | - |
|---|
| 277 | | - return IRQ_HANDLED; |
|---|
| 278 | | - } |
|---|
| 279 | | - |
|---|
| 280 | | - burst_len = min_t(unsigned int, |
|---|
| 281 | | - spicc->xfer_remain / spicc->bytes_per_word, |
|---|
| 282 | | - SPICC_BURST_MAX); |
|---|
| 283 | | - |
|---|
| 284 | | - /* Setup burst */ |
|---|
| 285 | | - meson_spicc_setup_burst(spicc, burst_len); |
|---|
| 286 | | - |
|---|
| 287 | | - /* Restart burst */ |
|---|
| 288 | | - writel_bits_relaxed(SPICC_XCH, SPICC_XCH, |
|---|
| 289 | | - spicc->base + SPICC_CONREG); |
|---|
| 290 | | - } |
|---|
| 291 | | - |
|---|
| 292 | | - /* Setup RX interrupt trigger */ |
|---|
| 293 | | - ctrl = meson_spicc_setup_rx_irq(spicc, ctrl); |
|---|
| 294 | | - |
|---|
| 295 | | - /* Reconfigure interrupts */ |
|---|
| 296 | | - writel(ctrl, spicc->base + SPICC_INTREG); |
|---|
| 293 | + /* Start burst */ |
|---|
| 294 | + writel_bits_relaxed(SPICC_XCH, SPICC_XCH, spicc->base + SPICC_CONREG); |
|---|
| 297 | 295 | |
|---|
| 298 | 296 | return IRQ_HANDLED; |
|---|
| 299 | 297 | } |
|---|
| 300 | 298 | |
|---|
| 301 | | -static u32 meson_spicc_setup_speed(struct meson_spicc_device *spicc, u32 conf, |
|---|
| 302 | | - u32 speed) |
|---|
| 299 | +static void meson_spicc_auto_io_delay(struct meson_spicc_device *spicc) |
|---|
| 303 | 300 | { |
|---|
| 304 | | - unsigned long parent, value; |
|---|
| 305 | | - unsigned int i, div; |
|---|
| 301 | + u32 div, hz; |
|---|
| 302 | + u32 mi_delay, cap_delay; |
|---|
| 303 | + u32 conf; |
|---|
| 306 | 304 | |
|---|
| 307 | | - parent = clk_get_rate(spicc->core); |
|---|
| 308 | | - |
|---|
| 309 | | - /* Find closest inferior/equal possible speed */ |
|---|
| 310 | | - for (i = 0 ; i < 7 ; ++i) { |
|---|
| 311 | | - /* 2^(data_rate+2) */ |
|---|
| 312 | | - value = parent >> (i + 2); |
|---|
| 313 | | - |
|---|
| 314 | | - if (value <= speed) |
|---|
| 315 | | - break; |
|---|
| 305 | + if (spicc->data->has_enhance_clk_div) { |
|---|
| 306 | + div = FIELD_GET(SPICC_ENH_DATARATE_MASK, |
|---|
| 307 | + readl_relaxed(spicc->base + SPICC_ENH_CTL0)); |
|---|
| 308 | + div++; |
|---|
| 309 | + div <<= 1; |
|---|
| 310 | + } else { |
|---|
| 311 | + div = FIELD_GET(SPICC_DATARATE_MASK, |
|---|
| 312 | + readl_relaxed(spicc->base + SPICC_CONREG)); |
|---|
| 313 | + div += 2; |
|---|
| 314 | + div = 1 << div; |
|---|
| 316 | 315 | } |
|---|
| 317 | 316 | |
|---|
| 318 | | - /* If provided speed it lower than max divider, use max divider */ |
|---|
| 319 | | - if (i > 7) { |
|---|
| 320 | | - div = 7; |
|---|
| 321 | | - dev_warn_once(&spicc->pdev->dev, "unable to get close to speed %u\n", |
|---|
| 322 | | - speed); |
|---|
| 323 | | - } else |
|---|
| 324 | | - div = i; |
|---|
| 317 | + mi_delay = SPICC_MI_NO_DELAY; |
|---|
| 318 | + cap_delay = SPICC_CAP_AHEAD_2_CYCLE; |
|---|
| 319 | + hz = clk_get_rate(spicc->clk); |
|---|
| 325 | 320 | |
|---|
| 326 | | - dev_dbg(&spicc->pdev->dev, "parent %lu, speed %u -> %lu (%u)\n", |
|---|
| 327 | | - parent, speed, value, div); |
|---|
| 321 | + if (hz >= 100000000) |
|---|
| 322 | + cap_delay = SPICC_CAP_DELAY_1_CYCLE; |
|---|
| 323 | + else if (hz >= 80000000) |
|---|
| 324 | + cap_delay = SPICC_CAP_NO_DELAY; |
|---|
| 325 | + else if (hz >= 40000000) |
|---|
| 326 | + cap_delay = SPICC_CAP_AHEAD_1_CYCLE; |
|---|
| 327 | + else if (div >= 16) |
|---|
| 328 | + mi_delay = SPICC_MI_DELAY_3_CYCLE; |
|---|
| 329 | + else if (div >= 8) |
|---|
| 330 | + mi_delay = SPICC_MI_DELAY_2_CYCLE; |
|---|
| 331 | + else if (div >= 6) |
|---|
| 332 | + mi_delay = SPICC_MI_DELAY_1_CYCLE; |
|---|
| 328 | 333 | |
|---|
| 329 | | - conf &= ~SPICC_DATARATE_MASK; |
|---|
| 330 | | - conf |= FIELD_PREP(SPICC_DATARATE_MASK, div); |
|---|
| 331 | | - |
|---|
| 332 | | - return conf; |
|---|
| 334 | + conf = readl_relaxed(spicc->base + SPICC_TESTREG); |
|---|
| 335 | + conf &= ~(SPICC_MO_DELAY_MASK | SPICC_MI_DELAY_MASK |
|---|
| 336 | + | SPICC_MI_CAP_DELAY_MASK); |
|---|
| 337 | + conf |= FIELD_PREP(SPICC_MI_DELAY_MASK, mi_delay); |
|---|
| 338 | + conf |= FIELD_PREP(SPICC_MI_CAP_DELAY_MASK, cap_delay); |
|---|
| 339 | + writel_relaxed(conf, spicc->base + SPICC_TESTREG); |
|---|
| 333 | 340 | } |
|---|
| 334 | 341 | |
|---|
| 335 | 342 | static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc, |
|---|
| .. | .. |
|---|
| 340 | 347 | /* Read original configuration */ |
|---|
| 341 | 348 | conf = conf_orig = readl_relaxed(spicc->base + SPICC_CONREG); |
|---|
| 342 | 349 | |
|---|
| 343 | | - /* Select closest divider */ |
|---|
| 344 | | - conf = meson_spicc_setup_speed(spicc, conf, xfer->speed_hz); |
|---|
| 345 | | - |
|---|
| 346 | 350 | /* Setup word width */ |
|---|
| 347 | 351 | conf &= ~SPICC_BITLENGTH_MASK; |
|---|
| 348 | 352 | conf |= FIELD_PREP(SPICC_BITLENGTH_MASK, |
|---|
| .. | .. |
|---|
| 351 | 355 | /* Ignore if unchanged */ |
|---|
| 352 | 356 | if (conf != conf_orig) |
|---|
| 353 | 357 | writel_relaxed(conf, spicc->base + SPICC_CONREG); |
|---|
| 358 | + |
|---|
| 359 | + clk_set_rate(spicc->clk, xfer->speed_hz); |
|---|
| 360 | + |
|---|
| 361 | + meson_spicc_auto_io_delay(spicc); |
|---|
| 362 | + |
|---|
| 363 | + writel_relaxed(0, spicc->base + SPICC_DMAREG); |
|---|
| 364 | +} |
|---|
| 365 | + |
|---|
| 366 | +static void meson_spicc_reset_fifo(struct meson_spicc_device *spicc) |
|---|
| 367 | +{ |
|---|
| 368 | + if (spicc->data->has_oen) |
|---|
| 369 | + writel_bits_relaxed(SPICC_ENH_MAIN_CLK_AO, |
|---|
| 370 | + SPICC_ENH_MAIN_CLK_AO, |
|---|
| 371 | + spicc->base + SPICC_ENH_CTL0); |
|---|
| 372 | + |
|---|
| 373 | + writel_bits_relaxed(SPICC_FIFORST_W1_MASK, SPICC_FIFORST_W1_MASK, |
|---|
| 374 | + spicc->base + SPICC_TESTREG); |
|---|
| 375 | + |
|---|
| 376 | + while (meson_spicc_rxready(spicc)) |
|---|
| 377 | + readl_relaxed(spicc->base + SPICC_RXDATA); |
|---|
| 378 | + |
|---|
| 379 | + if (spicc->data->has_oen) |
|---|
| 380 | + writel_bits_relaxed(SPICC_ENH_MAIN_CLK_AO, 0, |
|---|
| 381 | + spicc->base + SPICC_ENH_CTL0); |
|---|
| 354 | 382 | } |
|---|
| 355 | 383 | |
|---|
| 356 | 384 | static int meson_spicc_transfer_one(struct spi_master *master, |
|---|
| .. | .. |
|---|
| 358 | 386 | struct spi_transfer *xfer) |
|---|
| 359 | 387 | { |
|---|
| 360 | 388 | struct meson_spicc_device *spicc = spi_master_get_devdata(master); |
|---|
| 361 | | - unsigned int burst_len; |
|---|
| 362 | | - u32 irq = 0; |
|---|
| 363 | 389 | |
|---|
| 364 | 390 | /* Store current transfer */ |
|---|
| 365 | 391 | spicc->xfer = xfer; |
|---|
| .. | .. |
|---|
| 373 | 399 | spicc->bytes_per_word = |
|---|
| 374 | 400 | DIV_ROUND_UP(spicc->xfer->bits_per_word, 8); |
|---|
| 375 | 401 | |
|---|
| 402 | + if (xfer->len % spicc->bytes_per_word) |
|---|
| 403 | + return -EINVAL; |
|---|
| 404 | + |
|---|
| 376 | 405 | /* Setup transfer parameters */ |
|---|
| 377 | 406 | meson_spicc_setup_xfer(spicc, xfer); |
|---|
| 378 | 407 | |
|---|
| 379 | | - burst_len = min_t(unsigned int, |
|---|
| 380 | | - spicc->xfer_remain / spicc->bytes_per_word, |
|---|
| 381 | | - SPICC_BURST_MAX); |
|---|
| 408 | + meson_spicc_reset_fifo(spicc); |
|---|
| 382 | 409 | |
|---|
| 383 | | - meson_spicc_setup_burst(spicc, burst_len); |
|---|
| 384 | | - |
|---|
| 385 | | - irq = meson_spicc_setup_rx_irq(spicc, irq); |
|---|
| 410 | + /* Setup burst */ |
|---|
| 411 | + meson_spicc_setup_burst(spicc); |
|---|
| 386 | 412 | |
|---|
| 387 | 413 | /* Start burst */ |
|---|
| 388 | 414 | writel_bits_relaxed(SPICC_XCH, SPICC_XCH, spicc->base + SPICC_CONREG); |
|---|
| 389 | 415 | |
|---|
| 390 | 416 | /* Enable interrupts */ |
|---|
| 391 | | - writel_relaxed(irq, spicc->base + SPICC_INTREG); |
|---|
| 417 | + writel_relaxed(SPICC_TC_EN, spicc->base + SPICC_INTREG); |
|---|
| 392 | 418 | |
|---|
| 393 | 419 | return 1; |
|---|
| 394 | 420 | } |
|---|
| .. | .. |
|---|
| 398 | 424 | { |
|---|
| 399 | 425 | struct meson_spicc_device *spicc = spi_master_get_devdata(master); |
|---|
| 400 | 426 | struct spi_device *spi = message->spi; |
|---|
| 401 | | - u32 conf = 0; |
|---|
| 427 | + u32 conf = readl_relaxed(spicc->base + SPICC_CONREG) & SPICC_DATARATE_MASK; |
|---|
| 402 | 428 | |
|---|
| 403 | 429 | /* Store current message */ |
|---|
| 404 | 430 | spicc->message = message; |
|---|
| .. | .. |
|---|
| 435 | 461 | /* Select CS */ |
|---|
| 436 | 462 | conf |= FIELD_PREP(SPICC_CS_MASK, spi->chip_select); |
|---|
| 437 | 463 | |
|---|
| 438 | | - /* Default Clock rate core/4 */ |
|---|
| 439 | | - |
|---|
| 440 | 464 | /* Default 8bit word */ |
|---|
| 441 | 465 | conf |= FIELD_PREP(SPICC_BITLENGTH_MASK, 8 - 1); |
|---|
| 442 | 466 | |
|---|
| .. | .. |
|---|
| 445 | 469 | /* Setup no wait cycles by default */ |
|---|
| 446 | 470 | writel_relaxed(0, spicc->base + SPICC_PERIODREG); |
|---|
| 447 | 471 | |
|---|
| 448 | | - writel_bits_relaxed(BIT(24), BIT(24), spicc->base + SPICC_TESTREG); |
|---|
| 472 | + writel_bits_relaxed(SPICC_LBC_W1, 0, spicc->base + SPICC_TESTREG); |
|---|
| 449 | 473 | |
|---|
| 450 | 474 | return 0; |
|---|
| 451 | 475 | } |
|---|
| .. | .. |
|---|
| 453 | 477 | static int meson_spicc_unprepare_transfer(struct spi_master *master) |
|---|
| 454 | 478 | { |
|---|
| 455 | 479 | struct meson_spicc_device *spicc = spi_master_get_devdata(master); |
|---|
| 480 | + u32 conf = readl_relaxed(spicc->base + SPICC_CONREG) & SPICC_DATARATE_MASK; |
|---|
| 456 | 481 | |
|---|
| 457 | 482 | /* Disable all IRQs */ |
|---|
| 458 | 483 | writel(0, spicc->base + SPICC_INTREG); |
|---|
| 459 | 484 | |
|---|
| 460 | | - /* Disable controller */ |
|---|
| 461 | | - writel_bits_relaxed(SPICC_ENABLE, 0, spicc->base + SPICC_CONREG); |
|---|
| 462 | | - |
|---|
| 463 | 485 | device_reset_optional(&spicc->pdev->dev); |
|---|
| 486 | + |
|---|
| 487 | + /* Set default configuration, keeping datarate field */ |
|---|
| 488 | + writel_relaxed(conf, spicc->base + SPICC_CONREG); |
|---|
| 464 | 489 | |
|---|
| 465 | 490 | return 0; |
|---|
| 466 | 491 | } |
|---|
| 467 | 492 | |
|---|
| 468 | 493 | static int meson_spicc_setup(struct spi_device *spi) |
|---|
| 469 | 494 | { |
|---|
| 470 | | - int ret = 0; |
|---|
| 471 | | - |
|---|
| 472 | 495 | if (!spi->controller_state) |
|---|
| 473 | 496 | spi->controller_state = spi_master_get_devdata(spi->master); |
|---|
| 474 | | - else if (gpio_is_valid(spi->cs_gpio)) |
|---|
| 475 | | - goto out_gpio; |
|---|
| 476 | | - else if (spi->cs_gpio == -ENOENT) |
|---|
| 477 | | - return 0; |
|---|
| 478 | 497 | |
|---|
| 479 | | - if (gpio_is_valid(spi->cs_gpio)) { |
|---|
| 480 | | - ret = gpio_request(spi->cs_gpio, dev_name(&spi->dev)); |
|---|
| 481 | | - if (ret) { |
|---|
| 482 | | - dev_err(&spi->dev, "failed to request cs gpio\n"); |
|---|
| 483 | | - return ret; |
|---|
| 484 | | - } |
|---|
| 485 | | - } |
|---|
| 486 | | - |
|---|
| 487 | | -out_gpio: |
|---|
| 488 | | - ret = gpio_direction_output(spi->cs_gpio, |
|---|
| 489 | | - !(spi->mode & SPI_CS_HIGH)); |
|---|
| 490 | | - |
|---|
| 491 | | - return ret; |
|---|
| 498 | + return 0; |
|---|
| 492 | 499 | } |
|---|
| 493 | 500 | |
|---|
| 494 | 501 | static void meson_spicc_cleanup(struct spi_device *spi) |
|---|
| 495 | 502 | { |
|---|
| 496 | | - if (gpio_is_valid(spi->cs_gpio)) |
|---|
| 497 | | - gpio_free(spi->cs_gpio); |
|---|
| 498 | | - |
|---|
| 499 | 503 | spi->controller_state = NULL; |
|---|
| 504 | +} |
|---|
| 505 | + |
|---|
| 506 | +/* |
|---|
| 507 | + * The Clock Mux |
|---|
| 508 | + * x-----------------x x------------x x------\ |
|---|
| 509 | + * |---| pow2 fixed div |---| pow2 div |----| | |
|---|
| 510 | + * | x-----------------x x------------x | | |
|---|
| 511 | + * src ---| | mux |-- out |
|---|
| 512 | + * | x-----------------x x------------x | | |
|---|
| 513 | + * |---| enh fixed div |---| enh div |0---| | |
|---|
| 514 | + * x-----------------x x------------x x------/ |
|---|
| 515 | + * |
|---|
| 516 | + * Clk path for GX series: |
|---|
| 517 | + * src -> pow2 fixed div -> pow2 div -> out |
|---|
| 518 | + * |
|---|
| 519 | + * Clk path for AXG series: |
|---|
| 520 | + * src -> pow2 fixed div -> pow2 div -> mux -> out |
|---|
| 521 | + * src -> enh fixed div -> enh div -> mux -> out |
|---|
| 522 | + * |
|---|
| 523 | + * Clk path for G12A series: |
|---|
| 524 | + * pclk -> pow2 fixed div -> pow2 div -> mux -> out |
|---|
| 525 | + * pclk -> enh fixed div -> enh div -> mux -> out |
|---|
| 526 | + * |
|---|
| 527 | + * The pow2 divider is tied to the controller HW state, and the |
|---|
| 528 | + * divider is only valid when the controller is initialized. |
|---|
| 529 | + * |
|---|
| 530 | + * A set of clock ops is added to make sure we don't read/set this |
|---|
| 531 | + * clock rate while the controller is in an unknown state. |
|---|
| 532 | + */ |
|---|
| 533 | + |
|---|
| 534 | +static unsigned long meson_spicc_pow2_recalc_rate(struct clk_hw *hw, |
|---|
| 535 | + unsigned long parent_rate) |
|---|
| 536 | +{ |
|---|
| 537 | + struct clk_divider *divider = to_clk_divider(hw); |
|---|
| 538 | + struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider); |
|---|
| 539 | + |
|---|
| 540 | + if (!spicc->master->cur_msg) |
|---|
| 541 | + return 0; |
|---|
| 542 | + |
|---|
| 543 | + return clk_divider_ops.recalc_rate(hw, parent_rate); |
|---|
| 544 | +} |
|---|
| 545 | + |
|---|
| 546 | +static int meson_spicc_pow2_determine_rate(struct clk_hw *hw, |
|---|
| 547 | + struct clk_rate_request *req) |
|---|
| 548 | +{ |
|---|
| 549 | + struct clk_divider *divider = to_clk_divider(hw); |
|---|
| 550 | + struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider); |
|---|
| 551 | + |
|---|
| 552 | + if (!spicc->master->cur_msg) |
|---|
| 553 | + return -EINVAL; |
|---|
| 554 | + |
|---|
| 555 | + return clk_divider_ops.determine_rate(hw, req); |
|---|
| 556 | +} |
|---|
| 557 | + |
|---|
| 558 | +static int meson_spicc_pow2_set_rate(struct clk_hw *hw, unsigned long rate, |
|---|
| 559 | + unsigned long parent_rate) |
|---|
| 560 | +{ |
|---|
| 561 | + struct clk_divider *divider = to_clk_divider(hw); |
|---|
| 562 | + struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider); |
|---|
| 563 | + |
|---|
| 564 | + if (!spicc->master->cur_msg) |
|---|
| 565 | + return -EINVAL; |
|---|
| 566 | + |
|---|
| 567 | + return clk_divider_ops.set_rate(hw, rate, parent_rate); |
|---|
| 568 | +} |
|---|
| 569 | + |
|---|
| 570 | +const struct clk_ops meson_spicc_pow2_clk_ops = { |
|---|
| 571 | + .recalc_rate = meson_spicc_pow2_recalc_rate, |
|---|
| 572 | + .determine_rate = meson_spicc_pow2_determine_rate, |
|---|
| 573 | + .set_rate = meson_spicc_pow2_set_rate, |
|---|
| 574 | +}; |
|---|
| 575 | + |
|---|
| 576 | +static int meson_spicc_pow2_clk_init(struct meson_spicc_device *spicc) |
|---|
| 577 | +{ |
|---|
| 578 | + struct device *dev = &spicc->pdev->dev; |
|---|
| 579 | + struct clk_fixed_factor *pow2_fixed_div; |
|---|
| 580 | + struct clk_init_data init; |
|---|
| 581 | + struct clk *clk; |
|---|
| 582 | + struct clk_parent_data parent_data[2]; |
|---|
| 583 | + char name[64]; |
|---|
| 584 | + |
|---|
| 585 | + memset(&init, 0, sizeof(init)); |
|---|
| 586 | + memset(&parent_data, 0, sizeof(parent_data)); |
|---|
| 587 | + |
|---|
| 588 | + init.parent_data = parent_data; |
|---|
| 589 | + |
|---|
| 590 | + /* algorithm for pow2 div: rate = freq / 4 / (2 ^ N) */ |
|---|
| 591 | + |
|---|
| 592 | + pow2_fixed_div = devm_kzalloc(dev, sizeof(*pow2_fixed_div), GFP_KERNEL); |
|---|
| 593 | + if (!pow2_fixed_div) |
|---|
| 594 | + return -ENOMEM; |
|---|
| 595 | + |
|---|
| 596 | + snprintf(name, sizeof(name), "%s#pow2_fixed_div", dev_name(dev)); |
|---|
| 597 | + init.name = name; |
|---|
| 598 | + init.ops = &clk_fixed_factor_ops; |
|---|
| 599 | + init.flags = 0; |
|---|
| 600 | + if (spicc->data->has_pclk) |
|---|
| 601 | + parent_data[0].hw = __clk_get_hw(spicc->pclk); |
|---|
| 602 | + else |
|---|
| 603 | + parent_data[0].hw = __clk_get_hw(spicc->core); |
|---|
| 604 | + init.num_parents = 1; |
|---|
| 605 | + |
|---|
| 606 | + pow2_fixed_div->mult = 1, |
|---|
| 607 | + pow2_fixed_div->div = 4, |
|---|
| 608 | + pow2_fixed_div->hw.init = &init; |
|---|
| 609 | + |
|---|
| 610 | + clk = devm_clk_register(dev, &pow2_fixed_div->hw); |
|---|
| 611 | + if (WARN_ON(IS_ERR(clk))) |
|---|
| 612 | + return PTR_ERR(clk); |
|---|
| 613 | + |
|---|
| 614 | + snprintf(name, sizeof(name), "%s#pow2_div", dev_name(dev)); |
|---|
| 615 | + init.name = name; |
|---|
| 616 | + init.ops = &meson_spicc_pow2_clk_ops; |
|---|
| 617 | + /* |
|---|
| 618 | + * Set NOCACHE here to make sure we read the actual HW value |
|---|
| 619 | + * since we reset the HW after each transfer. |
|---|
| 620 | + */ |
|---|
| 621 | + init.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE; |
|---|
| 622 | + parent_data[0].hw = &pow2_fixed_div->hw; |
|---|
| 623 | + init.num_parents = 1; |
|---|
| 624 | + |
|---|
| 625 | + spicc->pow2_div.shift = 16, |
|---|
| 626 | + spicc->pow2_div.width = 3, |
|---|
| 627 | + spicc->pow2_div.flags = CLK_DIVIDER_POWER_OF_TWO, |
|---|
| 628 | + spicc->pow2_div.reg = spicc->base + SPICC_CONREG; |
|---|
| 629 | + spicc->pow2_div.hw.init = &init; |
|---|
| 630 | + |
|---|
| 631 | + spicc->clk = devm_clk_register(dev, &spicc->pow2_div.hw); |
|---|
| 632 | + if (WARN_ON(IS_ERR(spicc->clk))) |
|---|
| 633 | + return PTR_ERR(spicc->clk); |
|---|
| 634 | + |
|---|
| 635 | + return 0; |
|---|
| 636 | +} |
|---|
| 637 | + |
|---|
| 638 | +static int meson_spicc_enh_clk_init(struct meson_spicc_device *spicc) |
|---|
| 639 | +{ |
|---|
| 640 | + struct device *dev = &spicc->pdev->dev; |
|---|
| 641 | + struct clk_fixed_factor *enh_fixed_div; |
|---|
| 642 | + struct clk_divider *enh_div; |
|---|
| 643 | + struct clk_mux *mux; |
|---|
| 644 | + struct clk_init_data init; |
|---|
| 645 | + struct clk *clk; |
|---|
| 646 | + struct clk_parent_data parent_data[2]; |
|---|
| 647 | + char name[64]; |
|---|
| 648 | + |
|---|
| 649 | + memset(&init, 0, sizeof(init)); |
|---|
| 650 | + memset(&parent_data, 0, sizeof(parent_data)); |
|---|
| 651 | + |
|---|
| 652 | + init.parent_data = parent_data; |
|---|
| 653 | + |
|---|
| 654 | + /* algorithm for enh div: rate = freq / 2 / (N + 1) */ |
|---|
| 655 | + |
|---|
| 656 | + enh_fixed_div = devm_kzalloc(dev, sizeof(*enh_fixed_div), GFP_KERNEL); |
|---|
| 657 | + if (!enh_fixed_div) |
|---|
| 658 | + return -ENOMEM; |
|---|
| 659 | + |
|---|
| 660 | + snprintf(name, sizeof(name), "%s#enh_fixed_div", dev_name(dev)); |
|---|
| 661 | + init.name = name; |
|---|
| 662 | + init.ops = &clk_fixed_factor_ops; |
|---|
| 663 | + init.flags = 0; |
|---|
| 664 | + if (spicc->data->has_pclk) |
|---|
| 665 | + parent_data[0].hw = __clk_get_hw(spicc->pclk); |
|---|
| 666 | + else |
|---|
| 667 | + parent_data[0].hw = __clk_get_hw(spicc->core); |
|---|
| 668 | + init.num_parents = 1; |
|---|
| 669 | + |
|---|
| 670 | + enh_fixed_div->mult = 1, |
|---|
| 671 | + enh_fixed_div->div = 2, |
|---|
| 672 | + enh_fixed_div->hw.init = &init; |
|---|
| 673 | + |
|---|
| 674 | + clk = devm_clk_register(dev, &enh_fixed_div->hw); |
|---|
| 675 | + if (WARN_ON(IS_ERR(clk))) |
|---|
| 676 | + return PTR_ERR(clk); |
|---|
| 677 | + |
|---|
| 678 | + enh_div = devm_kzalloc(dev, sizeof(*enh_div), GFP_KERNEL); |
|---|
| 679 | + if (!enh_div) |
|---|
| 680 | + return -ENOMEM; |
|---|
| 681 | + |
|---|
| 682 | + snprintf(name, sizeof(name), "%s#enh_div", dev_name(dev)); |
|---|
| 683 | + init.name = name; |
|---|
| 684 | + init.ops = &clk_divider_ops; |
|---|
| 685 | + init.flags = CLK_SET_RATE_PARENT; |
|---|
| 686 | + parent_data[0].hw = &enh_fixed_div->hw; |
|---|
| 687 | + init.num_parents = 1; |
|---|
| 688 | + |
|---|
| 689 | + enh_div->shift = 16, |
|---|
| 690 | + enh_div->width = 8, |
|---|
| 691 | + enh_div->reg = spicc->base + SPICC_ENH_CTL0; |
|---|
| 692 | + enh_div->hw.init = &init; |
|---|
| 693 | + |
|---|
| 694 | + clk = devm_clk_register(dev, &enh_div->hw); |
|---|
| 695 | + if (WARN_ON(IS_ERR(clk))) |
|---|
| 696 | + return PTR_ERR(clk); |
|---|
| 697 | + |
|---|
| 698 | + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); |
|---|
| 699 | + if (!mux) |
|---|
| 700 | + return -ENOMEM; |
|---|
| 701 | + |
|---|
| 702 | + snprintf(name, sizeof(name), "%s#sel", dev_name(dev)); |
|---|
| 703 | + init.name = name; |
|---|
| 704 | + init.ops = &clk_mux_ops; |
|---|
| 705 | + parent_data[0].hw = &spicc->pow2_div.hw; |
|---|
| 706 | + parent_data[1].hw = &enh_div->hw; |
|---|
| 707 | + init.num_parents = 2; |
|---|
| 708 | + init.flags = CLK_SET_RATE_PARENT; |
|---|
| 709 | + |
|---|
| 710 | + mux->mask = 0x1, |
|---|
| 711 | + mux->shift = 24, |
|---|
| 712 | + mux->reg = spicc->base + SPICC_ENH_CTL0; |
|---|
| 713 | + mux->hw.init = &init; |
|---|
| 714 | + |
|---|
| 715 | + spicc->clk = devm_clk_register(dev, &mux->hw); |
|---|
| 716 | + if (WARN_ON(IS_ERR(spicc->clk))) |
|---|
| 717 | + return PTR_ERR(spicc->clk); |
|---|
| 718 | + |
|---|
| 719 | + return 0; |
|---|
| 500 | 720 | } |
|---|
| 501 | 721 | |
|---|
| 502 | 722 | static int meson_spicc_probe(struct platform_device *pdev) |
|---|
| 503 | 723 | { |
|---|
| 504 | 724 | struct spi_master *master; |
|---|
| 505 | 725 | struct meson_spicc_device *spicc; |
|---|
| 506 | | - struct resource *res; |
|---|
| 507 | | - int ret, irq, rate; |
|---|
| 726 | + int ret, irq; |
|---|
| 508 | 727 | |
|---|
| 509 | 728 | master = spi_alloc_master(&pdev->dev, sizeof(*spicc)); |
|---|
| 510 | 729 | if (!master) { |
|---|
| .. | .. |
|---|
| 514 | 733 | spicc = spi_master_get_devdata(master); |
|---|
| 515 | 734 | spicc->master = master; |
|---|
| 516 | 735 | |
|---|
| 736 | + spicc->data = of_device_get_match_data(&pdev->dev); |
|---|
| 737 | + if (!spicc->data) { |
|---|
| 738 | + dev_err(&pdev->dev, "failed to get match data\n"); |
|---|
| 739 | + ret = -EINVAL; |
|---|
| 740 | + goto out_master; |
|---|
| 741 | + } |
|---|
| 742 | + |
|---|
| 517 | 743 | spicc->pdev = pdev; |
|---|
| 518 | 744 | platform_set_drvdata(pdev, spicc); |
|---|
| 519 | 745 | |
|---|
| 520 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 521 | | - spicc->base = devm_ioremap_resource(&pdev->dev, res); |
|---|
| 746 | + spicc->base = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 522 | 747 | if (IS_ERR(spicc->base)) { |
|---|
| 523 | 748 | dev_err(&pdev->dev, "io resource mapping failed\n"); |
|---|
| 524 | 749 | ret = PTR_ERR(spicc->base); |
|---|
| 525 | 750 | goto out_master; |
|---|
| 526 | 751 | } |
|---|
| 752 | + |
|---|
| 753 | + /* Set master mode and enable controller */ |
|---|
| 754 | + writel_relaxed(SPICC_ENABLE | SPICC_MODE_MASTER, |
|---|
| 755 | + spicc->base + SPICC_CONREG); |
|---|
| 527 | 756 | |
|---|
| 528 | 757 | /* Disable all IRQs */ |
|---|
| 529 | 758 | writel_relaxed(0, spicc->base + SPICC_INTREG); |
|---|
| .. | .. |
|---|
| 548 | 777 | goto out_master; |
|---|
| 549 | 778 | } |
|---|
| 550 | 779 | |
|---|
| 780 | + if (spicc->data->has_pclk) { |
|---|
| 781 | + spicc->pclk = devm_clk_get(&pdev->dev, "pclk"); |
|---|
| 782 | + if (IS_ERR(spicc->pclk)) { |
|---|
| 783 | + dev_err(&pdev->dev, "pclk clock request failed\n"); |
|---|
| 784 | + ret = PTR_ERR(spicc->pclk); |
|---|
| 785 | + goto out_master; |
|---|
| 786 | + } |
|---|
| 787 | + } |
|---|
| 788 | + |
|---|
| 551 | 789 | ret = clk_prepare_enable(spicc->core); |
|---|
| 552 | 790 | if (ret) { |
|---|
| 553 | 791 | dev_err(&pdev->dev, "core clock enable failed\n"); |
|---|
| 554 | 792 | goto out_master; |
|---|
| 555 | 793 | } |
|---|
| 556 | | - rate = clk_get_rate(spicc->core); |
|---|
| 794 | + |
|---|
| 795 | + ret = clk_prepare_enable(spicc->pclk); |
|---|
| 796 | + if (ret) { |
|---|
| 797 | + dev_err(&pdev->dev, "pclk clock enable failed\n"); |
|---|
| 798 | + goto out_core_clk; |
|---|
| 799 | + } |
|---|
| 557 | 800 | |
|---|
| 558 | 801 | device_reset_optional(&pdev->dev); |
|---|
| 559 | 802 | |
|---|
| .. | .. |
|---|
| 565 | 808 | SPI_BPW_MASK(16) | |
|---|
| 566 | 809 | SPI_BPW_MASK(8); |
|---|
| 567 | 810 | master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX); |
|---|
| 568 | | - master->min_speed_hz = rate >> 9; |
|---|
| 811 | + master->min_speed_hz = spicc->data->min_speed_hz; |
|---|
| 812 | + master->max_speed_hz = spicc->data->max_speed_hz; |
|---|
| 569 | 813 | master->setup = meson_spicc_setup; |
|---|
| 570 | 814 | master->cleanup = meson_spicc_cleanup; |
|---|
| 571 | 815 | master->prepare_message = meson_spicc_prepare_message; |
|---|
| 572 | 816 | master->unprepare_transfer_hardware = meson_spicc_unprepare_transfer; |
|---|
| 573 | 817 | master->transfer_one = meson_spicc_transfer_one; |
|---|
| 818 | + master->use_gpio_descriptors = true; |
|---|
| 574 | 819 | |
|---|
| 575 | | - /* Setup max rate according to the Meson GX datasheet */ |
|---|
| 576 | | - if ((rate >> 2) > SPICC_MAX_FREQ) |
|---|
| 577 | | - master->max_speed_hz = SPICC_MAX_FREQ; |
|---|
| 578 | | - else |
|---|
| 579 | | - master->max_speed_hz = rate >> 2; |
|---|
| 820 | + meson_spicc_oen_enable(spicc); |
|---|
| 821 | + |
|---|
| 822 | + ret = meson_spicc_pow2_clk_init(spicc); |
|---|
| 823 | + if (ret) { |
|---|
| 824 | + dev_err(&pdev->dev, "pow2 clock registration failed\n"); |
|---|
| 825 | + goto out_clk; |
|---|
| 826 | + } |
|---|
| 827 | + |
|---|
| 828 | + if (spicc->data->has_enhance_clk_div) { |
|---|
| 829 | + ret = meson_spicc_enh_clk_init(spicc); |
|---|
| 830 | + if (ret) { |
|---|
| 831 | + dev_err(&pdev->dev, "clock registration failed\n"); |
|---|
| 832 | + goto out_clk; |
|---|
| 833 | + } |
|---|
| 834 | + } |
|---|
| 580 | 835 | |
|---|
| 581 | 836 | ret = devm_spi_register_master(&pdev->dev, master); |
|---|
| 582 | 837 | if (ret) { |
|---|
| .. | .. |
|---|
| 587 | 842 | return 0; |
|---|
| 588 | 843 | |
|---|
| 589 | 844 | out_clk: |
|---|
| 845 | + clk_disable_unprepare(spicc->pclk); |
|---|
| 846 | + |
|---|
| 847 | +out_core_clk: |
|---|
| 590 | 848 | clk_disable_unprepare(spicc->core); |
|---|
| 591 | 849 | |
|---|
| 592 | 850 | out_master: |
|---|
| .. | .. |
|---|
| 603 | 861 | writel(0, spicc->base + SPICC_CONREG); |
|---|
| 604 | 862 | |
|---|
| 605 | 863 | clk_disable_unprepare(spicc->core); |
|---|
| 864 | + clk_disable_unprepare(spicc->pclk); |
|---|
| 606 | 865 | |
|---|
| 607 | 866 | spi_master_put(spicc->master); |
|---|
| 608 | 867 | |
|---|
| 609 | 868 | return 0; |
|---|
| 610 | 869 | } |
|---|
| 611 | 870 | |
|---|
| 871 | +static const struct meson_spicc_data meson_spicc_gx_data = { |
|---|
| 872 | + .max_speed_hz = 30000000, |
|---|
| 873 | + .min_speed_hz = 325000, |
|---|
| 874 | + .fifo_size = 16, |
|---|
| 875 | +}; |
|---|
| 876 | + |
|---|
| 877 | +static const struct meson_spicc_data meson_spicc_axg_data = { |
|---|
| 878 | + .max_speed_hz = 80000000, |
|---|
| 879 | + .min_speed_hz = 325000, |
|---|
| 880 | + .fifo_size = 16, |
|---|
| 881 | + .has_oen = true, |
|---|
| 882 | + .has_enhance_clk_div = true, |
|---|
| 883 | +}; |
|---|
| 884 | + |
|---|
| 885 | +static const struct meson_spicc_data meson_spicc_g12a_data = { |
|---|
| 886 | + .max_speed_hz = 166666666, |
|---|
| 887 | + .min_speed_hz = 50000, |
|---|
| 888 | + .fifo_size = 15, |
|---|
| 889 | + .has_oen = true, |
|---|
| 890 | + .has_enhance_clk_div = true, |
|---|
| 891 | + .has_pclk = true, |
|---|
| 892 | +}; |
|---|
| 893 | + |
|---|
| 612 | 894 | static const struct of_device_id meson_spicc_of_match[] = { |
|---|
| 613 | | - { .compatible = "amlogic,meson-gx-spicc", }, |
|---|
| 614 | | - { .compatible = "amlogic,meson-axg-spicc", }, |
|---|
| 895 | + { |
|---|
| 896 | + .compatible = "amlogic,meson-gx-spicc", |
|---|
| 897 | + .data = &meson_spicc_gx_data, |
|---|
| 898 | + }, |
|---|
| 899 | + { |
|---|
| 900 | + .compatible = "amlogic,meson-axg-spicc", |
|---|
| 901 | + .data = &meson_spicc_axg_data, |
|---|
| 902 | + }, |
|---|
| 903 | + { |
|---|
| 904 | + .compatible = "amlogic,meson-g12a-spicc", |
|---|
| 905 | + .data = &meson_spicc_g12a_data, |
|---|
| 906 | + }, |
|---|
| 615 | 907 | { /* sentinel */ } |
|---|
| 616 | 908 | }; |
|---|
| 617 | 909 | MODULE_DEVICE_TABLE(of, meson_spicc_of_match); |
|---|