Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mtd: rawnand: macronix: Add support for deep power down mode

Macronix AD series support deep power down mode for a minimum
power consumption state.

Overload nand_suspend() & nand_resume() in Macronix specific code to
support deep power down mode.

Signed-off-by: Mason Yang <masonccyang@mxic.com.tw>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

authored by

Mason Yang and committed by
Miquel Raynal
19301d54 adc6162b

+74
+74
drivers/mtd/nand/raw/nand_macronix.c
··· 6 6 * Author: Boris Brezillon <boris.brezillon@free-electrons.com> 7 7 */ 8 8 9 + #include "linux/delay.h" 9 10 #include "internals.h" 10 11 11 12 #define MACRONIX_READ_RETRY_BIT BIT(0) ··· 28 27 #define MACRONIX_RANDOMIZER_MODE_EXIT \ 29 28 (MACRONIX_RANDOMIZER_RANDEN | \ 30 29 MACRONIX_RANDOMIZER_RANDOPT) 30 + 31 + #define MXIC_CMD_POWER_DOWN 0xB9 31 32 32 33 struct nand_onfi_vendor_macronix { 33 34 u8 reserved; ··· 246 243 chip->unlock_area = mxic_nand_unlock; 247 244 } 248 245 246 + static int nand_power_down_op(struct nand_chip *chip) 247 + { 248 + int ret; 249 + 250 + if (nand_has_exec_op(chip)) { 251 + struct nand_op_instr instrs[] = { 252 + NAND_OP_CMD(MXIC_CMD_POWER_DOWN, 0), 253 + }; 254 + 255 + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); 256 + 257 + ret = nand_exec_op(chip, &op); 258 + if (ret) 259 + return ret; 260 + 261 + } else { 262 + chip->legacy.cmdfunc(chip, MXIC_CMD_POWER_DOWN, -1, -1); 263 + } 264 + 265 + return 0; 266 + } 267 + 268 + static int mxic_nand_suspend(struct nand_chip *chip) 269 + { 270 + int ret; 271 + 272 + nand_select_target(chip, 0); 273 + ret = nand_power_down_op(chip); 274 + if (ret < 0) 275 + pr_err("Suspending MXIC NAND chip failed (%d)\n", ret); 276 + nand_deselect_target(chip); 277 + 278 + return ret; 279 + } 280 + 281 + static void mxic_nand_resume(struct nand_chip *chip) 282 + { 283 + /* 284 + * Toggle #CS pin to resume NAND device and don't care 285 + * of the others CLE, #WE, #RE pins status. 286 + * A NAND controller ensure it is able to assert/de-assert #CS 287 + * by sending any byte over the NAND bus. 288 + * i.e., 289 + * NAND power down command or reset command w/o R/B# status checking. 290 + */ 291 + nand_select_target(chip, 0); 292 + nand_power_down_op(chip); 293 + /* The minimum of a recovery time tRDP is 35 us */ 294 + usleep_range(35, 100); 295 + nand_deselect_target(chip); 296 + } 297 + 298 + static void macronix_nand_deep_power_down_support(struct nand_chip *chip) 299 + { 300 + int i; 301 + static const char * const deep_power_down_dev[] = { 302 + "MX30UF1G28AD", 303 + "MX30UF2G28AD", 304 + "MX30UF4G28AD", 305 + }; 306 + 307 + i = match_string(deep_power_down_dev, ARRAY_SIZE(deep_power_down_dev), 308 + chip->parameters.model); 309 + if (i < 0) 310 + return; 311 + 312 + chip->suspend = mxic_nand_suspend; 313 + chip->resume = mxic_nand_resume; 314 + } 315 + 249 316 static int macronix_nand_init(struct nand_chip *chip) 250 317 { 251 318 if (nand_is_slc(chip)) ··· 324 251 macronix_nand_fix_broken_get_timings(chip); 325 252 macronix_nand_onfi_init(chip); 326 253 macronix_nand_block_protection_support(chip); 254 + macronix_nand_deep_power_down_support(chip); 327 255 328 256 return 0; 329 257 }