linux-stable/include/linux/mmc/sdio_func.h

179 lines
5.5 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* include/linux/mmc/sdio_func.h
*
* Copyright 2007-2008 Pierre Ossman
*/
#ifndef LINUX_MMC_SDIO_FUNC_H
#define LINUX_MMC_SDIO_FUNC_H
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <linux/mmc/pm.h>
struct mmc_card;
struct sdio_func;
typedef void (sdio_irq_handler_t)(struct sdio_func *);
/*
* SDIO function CIS tuple (unknown to the core)
*/
struct sdio_func_tuple {
struct sdio_func_tuple *next;
unsigned char code;
unsigned char size;
unsigned char data[];
};
/*
* SDIO function devices
*/
struct sdio_func {
struct mmc_card *card; /* the card this device belongs to */
struct device dev; /* the device */
sdio_irq_handler_t *irq_handler; /* IRQ callback */
unsigned int num; /* function number */
unsigned char class; /* standard interface class */
unsigned short vendor; /* vendor id */
unsigned short device; /* device id */
unsigned max_blksize; /* maximum block size */
unsigned cur_blksize; /* current block size */
unsigned enable_timeout; /* max enable timeout in msec */
unsigned int state; /* function state */
#define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */
u8 *tmpbuf; /* DMA:able scratch buffer */
u8 major_rev; /* major revision number */
u8 minor_rev; /* minor revision number */
unsigned num_info; /* number of info strings */
const char **info; /* info strings */
struct sdio_func_tuple *tuples;
};
#define sdio_func_present(f) ((f)->state & SDIO_STATE_PRESENT)
#define sdio_func_set_present(f) ((f)->state |= SDIO_STATE_PRESENT)
#define sdio_func_id(f) (dev_name(&(f)->dev))
#define sdio_get_drvdata(f) dev_get_drvdata(&(f)->dev)
#define sdio_set_drvdata(f,d) dev_set_drvdata(&(f)->dev, d)
#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev)
/*
* SDIO function device driver
*/
struct sdio_driver {
char *name;
const struct sdio_device_id *id_table;
int (*probe)(struct sdio_func *, const struct sdio_device_id *);
void (*remove)(struct sdio_func *);
struct device_driver drv;
};
/**
* SDIO_DEVICE - macro used to describe a specific SDIO device
* @vend: the 16 bit manufacturer code
* @dev: the 16 bit function id
*
* This macro is used to create a struct sdio_device_id that matches a
* specific device. The class field will be set to SDIO_ANY_ID.
*/
#define SDIO_DEVICE(vend,dev) \
.class = SDIO_ANY_ID, \
.vendor = (vend), .device = (dev)
/**
* SDIO_DEVICE_CLASS - macro used to describe a specific SDIO device class
* @dev_class: the 8 bit standard interface code
*
* This macro is used to create a struct sdio_device_id that matches a
* specific standard SDIO function type. The vendor and device fields will
* be set to SDIO_ANY_ID.
*/
#define SDIO_DEVICE_CLASS(dev_class) \
.class = (dev_class), \
.vendor = SDIO_ANY_ID, .device = SDIO_ANY_ID
extern int sdio_register_driver(struct sdio_driver *);
extern void sdio_unregister_driver(struct sdio_driver *);
/**
* module_sdio_driver() - Helper macro for registering a SDIO driver
* @__sdio_driver: sdio_driver struct
*
* Helper macro for SDIO drivers which do not do anything special in module
* init/exit. This eliminates a lot of boilerplate. Each module may only
* use this macro once, and calling it replaces module_init() and module_exit()
*/
#define module_sdio_driver(__sdio_driver) \
module_driver(__sdio_driver, sdio_register_driver, \
sdio_unregister_driver)
/*
* SDIO I/O operations
*/
extern void sdio_claim_host(struct sdio_func *func);
extern void sdio_release_host(struct sdio_func *func);
extern int sdio_enable_func(struct sdio_func *func);
extern int sdio_disable_func(struct sdio_func *func);
extern int sdio_set_block_size(struct sdio_func *func, unsigned blksz);
extern int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler);
extern int sdio_release_irq(struct sdio_func *func);
extern unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz);
extern u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret);
extern u16 sdio_readw(struct sdio_func *func, unsigned int addr, int *err_ret);
extern u32 sdio_readl(struct sdio_func *func, unsigned int addr, int *err_ret);
extern int sdio_memcpy_fromio(struct sdio_func *func, void *dst,
unsigned int addr, int count);
extern int sdio_readsb(struct sdio_func *func, void *dst,
unsigned int addr, int count);
extern void sdio_writeb(struct sdio_func *func, u8 b,
unsigned int addr, int *err_ret);
extern void sdio_writew(struct sdio_func *func, u16 b,
unsigned int addr, int *err_ret);
extern void sdio_writel(struct sdio_func *func, u32 b,
unsigned int addr, int *err_ret);
extern u8 sdio_writeb_readb(struct sdio_func *func, u8 write_byte,
unsigned int addr, int *err_ret);
extern int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr,
void *src, int count);
extern int sdio_writesb(struct sdio_func *func, unsigned int addr,
void *src, int count);
extern unsigned char sdio_f0_readb(struct sdio_func *func,
unsigned int addr, int *err_ret);
extern void sdio_f0_writeb(struct sdio_func *func, unsigned char b,
unsigned int addr, int *err_ret);
extern mmc_pm_flag_t sdio_get_host_pm_caps(struct sdio_func *func);
extern int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags);
mmc: core: API to temporarily disable retuning for SDIO CRC errors Normally when the MMC core sees an "-EILSEQ" error returned by a host controller then it will trigger a retuning of the card. This is generally a good idea. However, if a command is expected to sometimes cause transfer errors then these transfer errors shouldn't cause a re-tuning. This re-tuning will be a needless waste of time. One example case where a transfer is expected to cause errors is when transitioning between idle (sometimes referred to as "sleep" in Broadcom code) and active state on certain Broadcom WiFi SDIO cards. Specifically if the card was already transitioning between states when the command was sent it could cause an error on the SDIO bus. Let's add an API that the SDIO function drivers can call that will temporarily disable the auto-tuning functionality. Then we can add a call to this in the Broadcom WiFi driver and any other driver that might have similar needs. NOTE: this makes the assumption that the card is already tuned well enough that it's OK to disable the auto-retuning during one of these error-prone situations. Presumably the driver code performing the error-prone transfer knows how to recover / retry from errors. ...and after we can get back to a state where transfers are no longer error-prone then we can enable the auto-retuning again. If we truly find ourselves in a case where the card needs to be retuned sometimes to handle one of these error-prone transfers then we can always try a few transfers first without auto-retuning and then re-try with auto-retuning if the first few fail. Without this change on rk3288-veyron-minnie I periodically see this in the logs of a machine just sitting there idle: dwmmc_rockchip ff0d0000.dwmmc: Successfully tuned phase to XYZ Cc: stable@vger.kernel.org #v4.18+ Signed-off-by: Douglas Anderson <dianders@chromium.org> Acked-by: Adrian Hunter <adrian.hunter@intel.com> Acked-by: Kalle Valo <kvalo@codeaurora.org> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
2019-06-17 17:56:50 +00:00
extern void sdio_retune_crc_disable(struct sdio_func *func);
extern void sdio_retune_crc_enable(struct sdio_func *func);
extern void sdio_retune_hold_now(struct sdio_func *func);
extern void sdio_retune_release(struct sdio_func *func);
#endif /* LINUX_MMC_SDIO_FUNC_H */