spibus: extend API: add cs_delay ivar, KEEP_CS and NO_SLEEP flags
These feature are required for an upcoming Apple MacBook topcase (HID over SPI) driver: A delay after toggling CS is required to avoid anomalies like an extra junk byte in front of the message. Keeping CS asserted is required to be able to read a status report after writing a command. (The device won't return the status if CS was deasserted.) Sleep is not allowed in the interrupt context where the Apple input driver runs its transactions. Use a flag to tell the SPI driver to avoid mtx_sleep. Reviewed by: manu (ok to SPI part of larger patch) MFC afret: 1 month Differential revision: https://reviews.freebsd.org/D29534
This commit is contained in:
parent
b344bd3a7d
commit
3c08673438
@ -34,9 +34,13 @@ struct spi_command {
|
|||||||
uint32_t tx_data_sz;
|
uint32_t tx_data_sz;
|
||||||
void *rx_data;
|
void *rx_data;
|
||||||
uint32_t rx_data_sz;
|
uint32_t rx_data_sz;
|
||||||
|
uint32_t flags;
|
||||||
};
|
};
|
||||||
#define SPI_COMMAND_INITIALIZER { 0 }
|
#define SPI_COMMAND_INITIALIZER { 0 }
|
||||||
|
|
||||||
|
#define SPI_FLAG_KEEP_CS 0x1 /* Keep chip select asserted */
|
||||||
|
#define SPI_FLAG_NO_SLEEP 0x2 /* Prevent driver from sleeping (use polling) */
|
||||||
|
|
||||||
#define SPI_CHIP_SELECT_HIGH 0x1 /* Chip select high (else low) */
|
#define SPI_CHIP_SELECT_HIGH 0x1 /* Chip select high (else low) */
|
||||||
|
|
||||||
#ifdef FDT
|
#ifdef FDT
|
||||||
|
@ -146,6 +146,9 @@ spibus_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
|
|||||||
case SPIBUS_IVAR_CLOCK:
|
case SPIBUS_IVAR_CLOCK:
|
||||||
*(uint32_t *)result = devi->clock;
|
*(uint32_t *)result = devi->clock;
|
||||||
break;
|
break;
|
||||||
|
case SPIBUS_IVAR_CS_DELAY:
|
||||||
|
*(uint32_t *)result = devi->cs_delay;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -174,6 +177,9 @@ spibus_write_ivar(device_t bus, device_t child, int which, uintptr_t value)
|
|||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
devi->mode = (uint32_t)value;
|
devi->mode = (uint32_t)value;
|
||||||
break;
|
break;
|
||||||
|
case SPIBUS_IVAR_CS_DELAY:
|
||||||
|
devi->cs_delay = (uint32_t)value;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@ struct spibus_ivar
|
|||||||
uint32_t cs;
|
uint32_t cs;
|
||||||
uint32_t mode;
|
uint32_t mode;
|
||||||
uint32_t clock;
|
uint32_t clock;
|
||||||
|
uint32_t cs_delay;
|
||||||
struct resource_list rl;
|
struct resource_list rl;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,6 +53,7 @@ enum {
|
|||||||
SPIBUS_IVAR_CS, /* chip select that we're on */
|
SPIBUS_IVAR_CS, /* chip select that we're on */
|
||||||
SPIBUS_IVAR_MODE, /* SPI mode (0-3) */
|
SPIBUS_IVAR_MODE, /* SPI mode (0-3) */
|
||||||
SPIBUS_IVAR_CLOCK, /* maximum clock freq for device */
|
SPIBUS_IVAR_CLOCK, /* maximum clock freq for device */
|
||||||
|
SPIBUS_IVAR_CS_DELAY, /* delay in microseconds after toggling chip select */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SPIBUS_ACCESSOR(A, B, T) \
|
#define SPIBUS_ACCESSOR(A, B, T) \
|
||||||
@ -71,6 +73,7 @@ spibus_set_ ## A(device_t dev, T t) \
|
|||||||
SPIBUS_ACCESSOR(cs, CS, uint32_t)
|
SPIBUS_ACCESSOR(cs, CS, uint32_t)
|
||||||
SPIBUS_ACCESSOR(mode, MODE, uint32_t)
|
SPIBUS_ACCESSOR(mode, MODE, uint32_t)
|
||||||
SPIBUS_ACCESSOR(clock, CLOCK, uint32_t)
|
SPIBUS_ACCESSOR(clock, CLOCK, uint32_t)
|
||||||
|
SPIBUS_ACCESSOR(cs_delay, CS_DELAY, uint32_t)
|
||||||
|
|
||||||
extern driver_t spibus_driver;
|
extern driver_t spibus_driver;
|
||||||
extern driver_t ofw_spibus_driver;
|
extern driver_t ofw_spibus_driver;
|
||||||
|
Loading…
Reference in New Issue
Block a user