Alex Dubov | baf8532 | 2008-02-09 10:20:54 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Sony MemoryStick support |
| 3 | * |
| 4 | * Copyright (C) 2007 Alex Dubov <oakad@yahoo.com> |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License version 2 as |
| 8 | * published by the Free Software Foundation. |
| 9 | * |
| 10 | */ |
| 11 | |
| 12 | #ifndef _MEMSTICK_H |
| 13 | #define _MEMSTICK_H |
| 14 | |
| 15 | #include <linux/workqueue.h> |
| 16 | #include <linux/scatterlist.h> |
| 17 | #include <linux/device.h> |
| 18 | |
| 19 | /*** Hardware based structures ***/ |
| 20 | |
| 21 | struct ms_status_register { |
| 22 | unsigned char reserved; |
| 23 | unsigned char interrupt; |
| 24 | #define MEMSTICK_INT_CMDNAK 0x0001 |
Alex Dubov | e1f1999 | 2008-03-10 11:43:37 -0700 | [diff] [blame] | 25 | #define MEMSTICK_INT_IOREQ 0x0008 |
| 26 | #define MEMSTICK_INT_IOBREQ 0x0010 |
Alex Dubov | baf8532 | 2008-02-09 10:20:54 -0800 | [diff] [blame] | 27 | #define MEMSTICK_INT_BREQ 0x0020 |
| 28 | #define MEMSTICK_INT_ERR 0x0040 |
| 29 | #define MEMSTICK_INT_CED 0x0080 |
| 30 | |
| 31 | unsigned char status0; |
| 32 | #define MEMSTICK_STATUS0_WP 0x0001 |
| 33 | #define MEMSTICK_STATUS0_SL 0x0002 |
| 34 | #define MEMSTICK_STATUS0_BF 0x0010 |
| 35 | #define MEMSTICK_STATUS0_BE 0x0020 |
| 36 | #define MEMSTICK_STATUS0_FB0 0x0040 |
| 37 | #define MEMSTICK_STATUS0_MB 0x0080 |
| 38 | |
| 39 | unsigned char status1; |
| 40 | #define MEMSTICK_STATUS1_UCFG 0x0001 |
| 41 | #define MEMSTICK_STATUS1_FGER 0x0002 |
| 42 | #define MEMSTICK_STATUS1_UCEX 0x0004 |
| 43 | #define MEMSTICK_STATUS1_EXER 0x0008 |
| 44 | #define MEMSTICK_STATUS1_UCDT 0x0010 |
| 45 | #define MEMSTICK_STATUS1_DTER 0x0020 |
| 46 | #define MEMSTICK_STATUS1_FBI 0x0040 |
| 47 | #define MEMSTICK_STATUS1_MB 0x0080 |
| 48 | } __attribute__((packed)); |
| 49 | |
| 50 | struct ms_id_register { |
| 51 | unsigned char type; |
Alex Dubov | e1f1999 | 2008-03-10 11:43:37 -0700 | [diff] [blame] | 52 | unsigned char if_mode; |
Alex Dubov | baf8532 | 2008-02-09 10:20:54 -0800 | [diff] [blame] | 53 | unsigned char category; |
| 54 | unsigned char class; |
| 55 | } __attribute__((packed)); |
| 56 | |
| 57 | struct ms_param_register { |
| 58 | unsigned char system; |
Alex Dubov | e1f1999 | 2008-03-10 11:43:37 -0700 | [diff] [blame] | 59 | #define MEMSTICK_SYS_ATEN 0xc0 |
| 60 | #define MEMSTICK_SYS_BAMD 0x80 |
| 61 | #define MEMSTICK_SYS_PAM 0x08 |
| 62 | |
Alex Dubov | baf8532 | 2008-02-09 10:20:54 -0800 | [diff] [blame] | 63 | unsigned char block_address_msb; |
| 64 | unsigned short block_address; |
| 65 | unsigned char cp; |
| 66 | #define MEMSTICK_CP_BLOCK 0x0000 |
| 67 | #define MEMSTICK_CP_PAGE 0x0020 |
| 68 | #define MEMSTICK_CP_EXTRA 0x0040 |
| 69 | #define MEMSTICK_CP_OVERWRITE 0x0080 |
| 70 | |
| 71 | unsigned char page_address; |
| 72 | } __attribute__((packed)); |
| 73 | |
| 74 | struct ms_extra_data_register { |
| 75 | unsigned char overwrite_flag; |
| 76 | #define MEMSTICK_OVERWRITE_UPDATA 0x0010 |
| 77 | #define MEMSTICK_OVERWRITE_PAGE 0x0060 |
| 78 | #define MEMSTICK_OVERWRITE_BLOCK 0x0080 |
| 79 | |
| 80 | unsigned char management_flag; |
| 81 | #define MEMSTICK_MANAGEMENT_SYSTEM 0x0004 |
| 82 | #define MEMSTICK_MANAGEMENT_TRANS_TABLE 0x0008 |
| 83 | #define MEMSTICK_MANAGEMENT_COPY 0x0010 |
| 84 | #define MEMSTICK_MANAGEMENT_ACCESS 0x0020 |
| 85 | |
| 86 | unsigned short logical_address; |
| 87 | } __attribute__((packed)); |
| 88 | |
| 89 | struct ms_register { |
| 90 | struct ms_status_register status; |
| 91 | struct ms_id_register id; |
| 92 | unsigned char reserved[8]; |
| 93 | struct ms_param_register param; |
| 94 | struct ms_extra_data_register extra_data; |
| 95 | } __attribute__((packed)); |
| 96 | |
| 97 | struct mspro_param_register { |
| 98 | unsigned char system; |
Alex Dubov | e1f1999 | 2008-03-10 11:43:37 -0700 | [diff] [blame] | 99 | #define MEMSTICK_SYS_SERIAL 0x80 |
| 100 | #define MEMSTICK_SYS_PAR4 0x00 |
| 101 | #define MEMSTICK_SYS_PAR8 0x40 |
| 102 | |
Alex Dubov | baf8532 | 2008-02-09 10:20:54 -0800 | [diff] [blame] | 103 | unsigned short data_count; |
| 104 | unsigned int data_address; |
Alex Dubov | e1f1999 | 2008-03-10 11:43:37 -0700 | [diff] [blame] | 105 | unsigned char tpc_param; |
| 106 | } __attribute__((packed)); |
| 107 | |
| 108 | struct mspro_io_info_register { |
| 109 | unsigned char version; |
| 110 | unsigned char io_category; |
| 111 | unsigned char current_req; |
| 112 | unsigned char card_opt_info; |
| 113 | unsigned char rdy_wait_time; |
| 114 | } __attribute__((packed)); |
| 115 | |
| 116 | struct mspro_io_func_register { |
| 117 | unsigned char func_enable; |
| 118 | unsigned char func_select; |
| 119 | unsigned char func_intmask; |
| 120 | unsigned char transfer_mode; |
| 121 | } __attribute__((packed)); |
| 122 | |
| 123 | struct mspro_io_cmd_register { |
| 124 | unsigned short tpc_param; |
| 125 | unsigned short data_count; |
| 126 | unsigned int data_address; |
Alex Dubov | baf8532 | 2008-02-09 10:20:54 -0800 | [diff] [blame] | 127 | } __attribute__((packed)); |
| 128 | |
| 129 | struct mspro_register { |
Alex Dubov | e1f1999 | 2008-03-10 11:43:37 -0700 | [diff] [blame] | 130 | struct ms_status_register status; |
| 131 | struct ms_id_register id; |
| 132 | unsigned char reserved0[8]; |
| 133 | struct mspro_param_register param; |
| 134 | unsigned char reserved1[8]; |
| 135 | struct mspro_io_info_register io_info; |
| 136 | struct mspro_io_func_register io_func; |
| 137 | unsigned char reserved2[7]; |
| 138 | struct mspro_io_cmd_register io_cmd; |
| 139 | unsigned char io_int; |
| 140 | unsigned char io_int_func; |
Alex Dubov | baf8532 | 2008-02-09 10:20:54 -0800 | [diff] [blame] | 141 | } __attribute__((packed)); |
| 142 | |
| 143 | struct ms_register_addr { |
| 144 | unsigned char r_offset; |
| 145 | unsigned char r_length; |
| 146 | unsigned char w_offset; |
| 147 | unsigned char w_length; |
| 148 | } __attribute__((packed)); |
| 149 | |
| 150 | enum { |
Alex Dubov | e1f1999 | 2008-03-10 11:43:37 -0700 | [diff] [blame] | 151 | MS_TPC_READ_MG_STATUS = 0x01, |
Alex Dubov | baf8532 | 2008-02-09 10:20:54 -0800 | [diff] [blame] | 152 | MS_TPC_READ_LONG_DATA = 0x02, |
| 153 | MS_TPC_READ_SHORT_DATA = 0x03, |
Alex Dubov | e1f1999 | 2008-03-10 11:43:37 -0700 | [diff] [blame] | 154 | MS_TPC_READ_MG_DATA = 0x03, |
Alex Dubov | baf8532 | 2008-02-09 10:20:54 -0800 | [diff] [blame] | 155 | MS_TPC_READ_REG = 0x04, |
Alex Dubov | e1f1999 | 2008-03-10 11:43:37 -0700 | [diff] [blame] | 156 | MS_TPC_READ_QUAD_DATA = 0x05, |
| 157 | MS_TPC_READ_IO_DATA = 0x05, |
Alex Dubov | baf8532 | 2008-02-09 10:20:54 -0800 | [diff] [blame] | 158 | MS_TPC_GET_INT = 0x07, |
| 159 | MS_TPC_SET_RW_REG_ADRS = 0x08, |
| 160 | MS_TPC_EX_SET_CMD = 0x09, |
Alex Dubov | e1f1999 | 2008-03-10 11:43:37 -0700 | [diff] [blame] | 161 | MS_TPC_WRITE_QUAD_DATA = 0x0a, |
| 162 | MS_TPC_WRITE_IO_DATA = 0x0a, |
Alex Dubov | baf8532 | 2008-02-09 10:20:54 -0800 | [diff] [blame] | 163 | MS_TPC_WRITE_REG = 0x0b, |
| 164 | MS_TPC_WRITE_SHORT_DATA = 0x0c, |
Alex Dubov | e1f1999 | 2008-03-10 11:43:37 -0700 | [diff] [blame] | 165 | MS_TPC_WRITE_MG_DATA = 0x0c, |
Alex Dubov | baf8532 | 2008-02-09 10:20:54 -0800 | [diff] [blame] | 166 | MS_TPC_WRITE_LONG_DATA = 0x0d, |
| 167 | MS_TPC_SET_CMD = 0x0e |
| 168 | }; |
| 169 | |
| 170 | enum { |
Alex Dubov | e1f1999 | 2008-03-10 11:43:37 -0700 | [diff] [blame] | 171 | MS_CMD_BLOCK_END = 0x33, |
| 172 | MS_CMD_RESET = 0x3c, |
| 173 | MS_CMD_BLOCK_WRITE = 0x55, |
| 174 | MS_CMD_SLEEP = 0x5a, |
| 175 | MS_CMD_BLOCK_ERASE = 0x99, |
| 176 | MS_CMD_BLOCK_READ = 0xaa, |
| 177 | MS_CMD_CLEAR_BUF = 0xc3, |
| 178 | MS_CMD_FLASH_STOP = 0xcc, |
| 179 | MS_CMD_LOAD_ID = 0x60, |
| 180 | MS_CMD_CMP_ICV = 0x7f, |
| 181 | MSPRO_CMD_FORMAT = 0x10, |
| 182 | MSPRO_CMD_SLEEP = 0x11, |
| 183 | MSPRO_CMD_WAKEUP = 0x12, |
| 184 | MSPRO_CMD_READ_DATA = 0x20, |
| 185 | MSPRO_CMD_WRITE_DATA = 0x21, |
| 186 | MSPRO_CMD_READ_ATRB = 0x24, |
| 187 | MSPRO_CMD_STOP = 0x25, |
| 188 | MSPRO_CMD_ERASE = 0x26, |
| 189 | MSPRO_CMD_READ_QUAD = 0x27, |
| 190 | MSPRO_CMD_WRITE_QUAD = 0x28, |
| 191 | MSPRO_CMD_SET_IBD = 0x46, |
| 192 | MSPRO_CMD_GET_IBD = 0x47, |
| 193 | MSPRO_CMD_IN_IO_DATA = 0xb0, |
| 194 | MSPRO_CMD_OUT_IO_DATA = 0xb1, |
| 195 | MSPRO_CMD_READ_IO_ATRB = 0xb2, |
| 196 | MSPRO_CMD_IN_IO_FIFO = 0xb3, |
| 197 | MSPRO_CMD_OUT_IO_FIFO = 0xb4, |
| 198 | MSPRO_CMD_IN_IOM = 0xb5, |
| 199 | MSPRO_CMD_OUT_IOM = 0xb6, |
Alex Dubov | baf8532 | 2008-02-09 10:20:54 -0800 | [diff] [blame] | 200 | }; |
| 201 | |
| 202 | /*** Driver structures and functions ***/ |
| 203 | |
| 204 | #define MEMSTICK_PART_SHIFT 3 |
| 205 | |
| 206 | enum memstick_param { MEMSTICK_POWER = 1, MEMSTICK_INTERFACE }; |
| 207 | |
| 208 | #define MEMSTICK_POWER_OFF 0 |
| 209 | #define MEMSTICK_POWER_ON 1 |
| 210 | |
| 211 | #define MEMSTICK_SERIAL 0 |
Alex Dubov | e1f1999 | 2008-03-10 11:43:37 -0700 | [diff] [blame] | 212 | #define MEMSTICK_PAR4 1 |
| 213 | #define MEMSTICK_PAR8 2 |
Alex Dubov | baf8532 | 2008-02-09 10:20:54 -0800 | [diff] [blame] | 214 | |
| 215 | struct memstick_host; |
| 216 | struct memstick_driver; |
| 217 | |
| 218 | #define MEMSTICK_MATCH_ALL 0x01 |
| 219 | |
| 220 | #define MEMSTICK_TYPE_LEGACY 0xff |
| 221 | #define MEMSTICK_TYPE_DUO 0x00 |
| 222 | #define MEMSTICK_TYPE_PRO 0x01 |
| 223 | |
| 224 | #define MEMSTICK_CATEGORY_STORAGE 0xff |
| 225 | #define MEMSTICK_CATEGORY_STORAGE_DUO 0x00 |
| 226 | |
| 227 | #define MEMSTICK_CLASS_GENERIC 0xff |
| 228 | #define MEMSTICK_CLASS_GENERIC_DUO 0x00 |
| 229 | |
| 230 | |
| 231 | struct memstick_device_id { |
| 232 | unsigned char match_flags; |
| 233 | unsigned char type; |
| 234 | unsigned char category; |
| 235 | unsigned char class; |
| 236 | }; |
| 237 | |
| 238 | struct memstick_request { |
| 239 | unsigned char tpc; |
| 240 | unsigned char data_dir:1, |
| 241 | need_card_int:1, |
Alex Dubov | e1f1999 | 2008-03-10 11:43:37 -0700 | [diff] [blame] | 242 | long_data:1; |
Alex Dubov | baf8532 | 2008-02-09 10:20:54 -0800 | [diff] [blame] | 243 | unsigned char int_reg; |
| 244 | int error; |
| 245 | union { |
| 246 | struct scatterlist sg; |
| 247 | struct { |
| 248 | unsigned char data_len; |
| 249 | unsigned char data[15]; |
| 250 | }; |
| 251 | }; |
| 252 | }; |
| 253 | |
| 254 | struct memstick_dev { |
| 255 | struct memstick_device_id id; |
| 256 | struct memstick_host *host; |
| 257 | struct ms_register_addr reg_addr; |
| 258 | struct completion mrq_complete; |
| 259 | struct memstick_request current_mrq; |
| 260 | |
| 261 | /* Check that media driver is still willing to operate the device. */ |
| 262 | int (*check)(struct memstick_dev *card); |
| 263 | /* Get next request from the media driver. */ |
| 264 | int (*next_request)(struct memstick_dev *card, |
| 265 | struct memstick_request **mrq); |
| 266 | |
| 267 | struct device dev; |
| 268 | }; |
| 269 | |
| 270 | struct memstick_host { |
| 271 | struct mutex lock; |
| 272 | unsigned int id; |
| 273 | unsigned int caps; |
Alex Dubov | e1f1999 | 2008-03-10 11:43:37 -0700 | [diff] [blame] | 274 | #define MEMSTICK_CAP_AUTO_GET_INT 1 |
| 275 | #define MEMSTICK_CAP_PAR4 2 |
| 276 | #define MEMSTICK_CAP_PAR8 4 |
Alex Dubov | baf8532 | 2008-02-09 10:20:54 -0800 | [diff] [blame] | 277 | |
| 278 | struct work_struct media_checker; |
| 279 | struct class_device cdev; |
| 280 | |
| 281 | struct memstick_dev *card; |
| 282 | unsigned int retries; |
| 283 | |
| 284 | /* Notify the host that some requests are pending. */ |
| 285 | void (*request)(struct memstick_host *host); |
| 286 | /* Set host IO parameters (power, clock, etc). */ |
| 287 | void (*set_param)(struct memstick_host *host, |
| 288 | enum memstick_param param, |
| 289 | int value); |
| 290 | unsigned long private[0] ____cacheline_aligned; |
| 291 | }; |
| 292 | |
| 293 | struct memstick_driver { |
| 294 | struct memstick_device_id *id_table; |
| 295 | int (*probe)(struct memstick_dev *card); |
| 296 | void (*remove)(struct memstick_dev *card); |
| 297 | int (*suspend)(struct memstick_dev *card, |
| 298 | pm_message_t state); |
| 299 | int (*resume)(struct memstick_dev *card); |
| 300 | |
| 301 | struct device_driver driver; |
| 302 | }; |
| 303 | |
| 304 | int memstick_register_driver(struct memstick_driver *drv); |
| 305 | void memstick_unregister_driver(struct memstick_driver *drv); |
| 306 | |
| 307 | struct memstick_host *memstick_alloc_host(unsigned int extra, |
| 308 | struct device *dev); |
| 309 | |
| 310 | int memstick_add_host(struct memstick_host *host); |
| 311 | void memstick_remove_host(struct memstick_host *host); |
| 312 | void memstick_free_host(struct memstick_host *host); |
| 313 | void memstick_detect_change(struct memstick_host *host); |
Alex Dubov | d114ad5 | 2008-03-10 11:43:38 -0700 | [diff] [blame] | 314 | void memstick_suspend_host(struct memstick_host *host); |
| 315 | void memstick_resume_host(struct memstick_host *host); |
Alex Dubov | baf8532 | 2008-02-09 10:20:54 -0800 | [diff] [blame] | 316 | |
| 317 | void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc, |
| 318 | struct scatterlist *sg); |
| 319 | void memstick_init_req(struct memstick_request *mrq, unsigned char tpc, |
| 320 | void *buf, size_t length); |
| 321 | int memstick_next_req(struct memstick_host *host, |
| 322 | struct memstick_request **mrq); |
| 323 | void memstick_new_req(struct memstick_host *host); |
| 324 | |
| 325 | int memstick_set_rw_addr(struct memstick_dev *card); |
| 326 | |
| 327 | static inline void *memstick_priv(struct memstick_host *host) |
| 328 | { |
| 329 | return (void *)host->private; |
| 330 | } |
| 331 | |
| 332 | static inline void *memstick_get_drvdata(struct memstick_dev *card) |
| 333 | { |
| 334 | return dev_get_drvdata(&card->dev); |
| 335 | } |
| 336 | |
| 337 | static inline void memstick_set_drvdata(struct memstick_dev *card, void *data) |
| 338 | { |
| 339 | dev_set_drvdata(&card->dev, data); |
| 340 | } |
| 341 | |
| 342 | #endif |