Skip to content

Commit 78b435c

Browse files
andy-shevbroonie
authored andcommitted
spi: pxa2xx: Introduce __lpss_ssp_update_priv() helper
In a few places we repeat RMW IO operations on LPSS private registers. Let's introduce a helper to make the code better to read and maintain. Signed-off-by: Andy Shevchenko <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 9a8afbe commit 78b435c

File tree

1 file changed

+40
-48
lines changed

1 file changed

+40
-48
lines changed

drivers/spi/spi-pxa2xx.c

Lines changed: 40 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,9 @@ struct chip_data {
7373
#define LPSS_CAPS_CS_EN_MASK (0xf << LPSS_CAPS_CS_EN_SHIFT)
7474

7575
#define LPSS_PRIV_CLOCK_GATE 0x38
76-
#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK 0x3
77-
#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON 0x3
76+
#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK 0x3
77+
#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON 0x3
78+
#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_OFF 0x0
7879

7980
struct lpss_config {
8081
/* LPSS offset from drv_data->ioaddr */
@@ -321,6 +322,20 @@ static void __lpss_ssp_write_priv(struct driver_data *drv_data,
321322
writel(value, drv_data->lpss_base + offset);
322323
}
323324

325+
static bool __lpss_ssp_update_priv(struct driver_data *drv_data, unsigned int offset,
326+
u32 mask, u32 value)
327+
{
328+
u32 new, curr;
329+
330+
curr = __lpss_ssp_read_priv(drv_data, offset);
331+
new = (curr & ~mask) | (value & mask);
332+
if (new == curr)
333+
return false;
334+
335+
__lpss_ssp_write_priv(drv_data, offset, new);
336+
return true;
337+
}
338+
324339
/*
325340
* lpss_ssp_setup - perform LPSS SSP specific setup
326341
* @drv_data: pointer to the driver private data
@@ -337,21 +352,16 @@ static void lpss_ssp_setup(struct driver_data *drv_data)
337352
drv_data->lpss_base = drv_data->ssp->mmio_base + config->offset;
338353

339354
/* Enable software chip select control */
340-
value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl);
341-
value &= ~(LPSS_CS_CONTROL_SW_MODE | LPSS_CS_CONTROL_CS_HIGH);
342-
value |= LPSS_CS_CONTROL_SW_MODE | LPSS_CS_CONTROL_CS_HIGH;
343-
__lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
355+
value = LPSS_CS_CONTROL_SW_MODE | LPSS_CS_CONTROL_CS_HIGH;
356+
__lpss_ssp_update_priv(drv_data, config->reg_cs_ctrl, value, value);
344357

345358
/* Enable multiblock DMA transfers */
346359
if (drv_data->controller_info->enable_dma) {
347-
__lpss_ssp_write_priv(drv_data, config->reg_ssp, 1);
360+
__lpss_ssp_update_priv(drv_data, config->reg_ssp, BIT(0), BIT(0));
348361

349362
if (config->reg_general >= 0) {
350-
value = __lpss_ssp_read_priv(drv_data,
351-
config->reg_general);
352-
value |= LPSS_GENERAL_REG_RXTO_HOLDOFF_DISABLE;
353-
__lpss_ssp_write_priv(drv_data,
354-
config->reg_general, value);
363+
value = LPSS_GENERAL_REG_RXTO_HOLDOFF_DISABLE;
364+
__lpss_ssp_update_priv(drv_data, config->reg_general, value, value);
355365
}
356366
}
357367
}
@@ -361,65 +371,47 @@ static void lpss_ssp_select_cs(struct spi_device *spi,
361371
{
362372
struct driver_data *drv_data =
363373
spi_controller_get_devdata(spi->controller);
364-
u32 value, cs;
374+
u32 cs;
365375

366-
if (!config->cs_sel_mask)
376+
cs = spi_get_chipselect(spi, 0) << config->cs_sel_shift;
377+
if (!__lpss_ssp_update_priv(drv_data, config->reg_cs_ctrl, config->cs_sel_mask, cs))
367378
return;
368379

369-
value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl);
370-
371-
cs = spi_get_chipselect(spi, 0);
372-
cs <<= config->cs_sel_shift;
373-
if (cs != (value & config->cs_sel_mask)) {
374-
/*
375-
* When switching another chip select output active the
376-
* output must be selected first and wait 2 ssp_clk cycles
377-
* before changing state to active. Otherwise a short
378-
* glitch will occur on the previous chip select since
379-
* output select is latched but state control is not.
380-
*/
381-
value &= ~config->cs_sel_mask;
382-
value |= cs;
383-
__lpss_ssp_write_priv(drv_data,
384-
config->reg_cs_ctrl, value);
385-
ndelay(1000000000 /
386-
(drv_data->controller->max_speed_hz / 2));
387-
}
380+
/*
381+
* When switching another chip select output active the output must be
382+
* selected first and wait 2 ssp_clk cycles before changing state to
383+
* active. Otherwise a short glitch will occur on the previous chip
384+
* select since output select is latched but state control is not.
385+
*/
386+
ndelay(1000000000 / (drv_data->controller->max_speed_hz / 2));
388387
}
389388

390389
static void lpss_ssp_cs_control(struct spi_device *spi, bool enable)
391390
{
392391
struct driver_data *drv_data =
393392
spi_controller_get_devdata(spi->controller);
394393
const struct lpss_config *config;
395-
u32 value;
394+
u32 mask;
396395

397396
config = lpss_get_config(drv_data);
398397

399398
if (enable)
400399
lpss_ssp_select_cs(spi, config);
401400

402-
value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl);
403-
if (enable)
404-
value &= ~LPSS_CS_CONTROL_CS_HIGH;
405-
else
406-
value |= LPSS_CS_CONTROL_CS_HIGH;
407-
__lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
401+
mask = LPSS_CS_CONTROL_CS_HIGH;
402+
__lpss_ssp_update_priv(drv_data, config->reg_cs_ctrl, mask, enable ? mask : 0);
408403
if (config->cs_clk_stays_gated) {
409-
u32 clkgate;
410-
411404
/*
412405
* Changing CS alone when dynamic clock gating is on won't
413406
* actually flip CS at that time. This ruins SPI transfers
414407
* that specify delays, or have no data. Toggle the clock mode
415408
* to force on briefly to poke the CS pin to move.
416409
*/
417-
clkgate = __lpss_ssp_read_priv(drv_data, LPSS_PRIV_CLOCK_GATE);
418-
value = (clkgate & ~LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK) |
419-
LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON;
420-
421-
__lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, value);
422-
__lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, clkgate);
410+
mask = LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK;
411+
if (__lpss_ssp_update_priv(drv_data, LPSS_PRIV_CLOCK_GATE, mask,
412+
LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON))
413+
__lpss_ssp_update_priv(drv_data, LPSS_PRIV_CLOCK_GATE, mask,
414+
LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_OFF);
423415
}
424416
}
425417

0 commit comments

Comments
 (0)