.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver |
---|
3 | 4 | * |
---|
.. | .. |
---|
5 | 6 | * |
---|
6 | 7 | * Current driver maintained by Ben Dooks and Simtec Electronics |
---|
7 | 8 | * Copyright (C) 2008 Simtec Electronics <ben-linux@fluff.org> |
---|
8 | | - * |
---|
9 | | - * This program is free software; you can redistribute it and/or modify |
---|
10 | | - * it under the terms of the GNU General Public License version 2 as |
---|
11 | | - * published by the Free Software Foundation. |
---|
12 | 9 | */ |
---|
13 | 10 | |
---|
14 | 11 | #include <linux/module.h> |
---|
.. | .. |
---|
26 | 23 | #include <linux/io.h> |
---|
27 | 24 | #include <linux/of.h> |
---|
28 | 25 | #include <linux/of_device.h> |
---|
29 | | -#include <linux/of_gpio.h> |
---|
30 | 26 | #include <linux/mmc/slot-gpio.h> |
---|
31 | | - |
---|
32 | | -#include <plat/gpio-cfg.h> |
---|
33 | | -#include <mach/dma.h> |
---|
34 | | -#include <mach/gpio-samsung.h> |
---|
35 | | - |
---|
36 | 27 | #include <linux/platform_data/mmc-s3cmci.h> |
---|
37 | 28 | |
---|
38 | 29 | #include "s3cmci.h" |
---|
.. | .. |
---|
154 | 145 | |
---|
155 | 146 | static void dbg_dumpregs(struct s3cmci_host *host, char *prefix) |
---|
156 | 147 | { |
---|
157 | | - u32 con, pre, cmdarg, cmdcon, cmdsta, r0, r1, r2, r3, timer, bsize; |
---|
158 | | - u32 datcon, datcnt, datsta, fsta, imask; |
---|
| 148 | + u32 con, pre, cmdarg, cmdcon, cmdsta, r0, r1, r2, r3, timer; |
---|
| 149 | + u32 datcon, datcnt, datsta, fsta; |
---|
159 | 150 | |
---|
160 | 151 | con = readl(host->base + S3C2410_SDICON); |
---|
161 | 152 | pre = readl(host->base + S3C2410_SDIPRE); |
---|
.. | .. |
---|
167 | 158 | r2 = readl(host->base + S3C2410_SDIRSP2); |
---|
168 | 159 | r3 = readl(host->base + S3C2410_SDIRSP3); |
---|
169 | 160 | timer = readl(host->base + S3C2410_SDITIMER); |
---|
170 | | - bsize = readl(host->base + S3C2410_SDIBSIZE); |
---|
171 | 161 | datcon = readl(host->base + S3C2410_SDIDCON); |
---|
172 | 162 | datcnt = readl(host->base + S3C2410_SDIDCNT); |
---|
173 | 163 | datsta = readl(host->base + S3C2410_SDIDSTA); |
---|
174 | 164 | fsta = readl(host->base + S3C2410_SDIFSTA); |
---|
175 | | - imask = readl(host->base + host->sdiimsk); |
---|
176 | 165 | |
---|
177 | 166 | dbg(host, dbg_debug, "%s CON:[%08x] PRE:[%08x] TMR:[%08x]\n", |
---|
178 | 167 | prefix, con, pre, timer); |
---|
.. | .. |
---|
311 | 300 | static void s3cmci_check_sdio_irq(struct s3cmci_host *host) |
---|
312 | 301 | { |
---|
313 | 302 | if (host->sdio_irqen) { |
---|
314 | | - if (gpio_get_value(S3C2410_GPE(8)) == 0) { |
---|
| 303 | + if (host->pdata->bus[3] && |
---|
| 304 | + gpiod_get_value(host->pdata->bus[3]) == 0) { |
---|
315 | 305 | pr_debug("%s: signalling irq\n", __func__); |
---|
316 | 306 | mmc_signal_sdio_irq(host->mmc); |
---|
317 | 307 | } |
---|
.. | .. |
---|
400 | 390 | local_irq_restore(flags); |
---|
401 | 391 | } |
---|
402 | 392 | |
---|
403 | | -/** |
---|
404 | | - * |
---|
405 | | - */ |
---|
406 | 393 | static void s3cmci_disable_irq(struct s3cmci_host *host, bool transfer) |
---|
407 | 394 | { |
---|
408 | 395 | unsigned long flags; |
---|
.. | .. |
---|
962 | 949 | { |
---|
963 | 950 | u32 dcon, imsk, stoptries = 3; |
---|
964 | 951 | |
---|
965 | | - /* write DCON register */ |
---|
966 | | - |
---|
967 | | - if (!data) { |
---|
968 | | - writel(0, host->base + S3C2410_SDIDCON); |
---|
969 | | - return 0; |
---|
970 | | - } |
---|
971 | | - |
---|
972 | 952 | if ((data->blksz & 3) != 0) { |
---|
973 | 953 | /* We cannot deal with unaligned blocks with more than |
---|
974 | 954 | * one block being transferred. */ |
---|
.. | .. |
---|
1217 | 1197 | switch (ios->power_mode) { |
---|
1218 | 1198 | case MMC_POWER_ON: |
---|
1219 | 1199 | case MMC_POWER_UP: |
---|
1220 | | - /* Configure GPE5...GPE10 pins in SD mode */ |
---|
1221 | | - if (!host->pdev->dev.of_node) |
---|
1222 | | - s3c_gpio_cfgall_range(S3C2410_GPE(5), 6, S3C_GPIO_SFN(2), |
---|
1223 | | - S3C_GPIO_PULL_NONE); |
---|
1224 | | - |
---|
1225 | | - if (host->pdata->set_power) |
---|
1226 | | - host->pdata->set_power(ios->power_mode, ios->vdd); |
---|
1227 | | - |
---|
1228 | 1200 | if (!host->is2440) |
---|
1229 | 1201 | mci_con |= S3C2410_SDICON_FIFORESET; |
---|
1230 | | - |
---|
1231 | 1202 | break; |
---|
1232 | 1203 | |
---|
1233 | 1204 | case MMC_POWER_OFF: |
---|
1234 | 1205 | default: |
---|
1235 | | - if (!host->pdev->dev.of_node) |
---|
1236 | | - gpio_direction_output(S3C2410_GPE(5), 0); |
---|
1237 | | - |
---|
1238 | 1206 | if (host->is2440) |
---|
1239 | 1207 | mci_con |= S3C2440_SDICON_SDRESET; |
---|
1240 | | - |
---|
1241 | | - if (host->pdata->set_power) |
---|
1242 | | - host->pdata->set_power(ios->power_mode, ios->vdd); |
---|
1243 | | - |
---|
1244 | 1208 | break; |
---|
1245 | 1209 | } |
---|
| 1210 | + |
---|
| 1211 | + if (host->pdata->set_power) |
---|
| 1212 | + host->pdata->set_power(ios->power_mode, ios->vdd); |
---|
1246 | 1213 | |
---|
1247 | 1214 | s3cmci_set_clk(host, ios); |
---|
1248 | 1215 | |
---|
.. | .. |
---|
1321 | 1288 | .enable_sdio_irq = s3cmci_enable_sdio_irq, |
---|
1322 | 1289 | }; |
---|
1323 | 1290 | |
---|
1324 | | -static struct s3c24xx_mci_pdata s3cmci_def_pdata = { |
---|
1325 | | - /* This is currently here to avoid a number of if (host->pdata) |
---|
1326 | | - * checks. Any zero fields to ensure reasonable defaults are picked. */ |
---|
1327 | | - .no_wprotect = 1, |
---|
1328 | | - .no_detect = 1, |
---|
1329 | | -}; |
---|
1330 | | - |
---|
1331 | 1291 | #ifdef CONFIG_ARM_S3C24XX_CPUFREQ |
---|
1332 | 1292 | |
---|
1333 | 1293 | static int s3cmci_cpufreq_transition(struct notifier_block *nb, |
---|
.. | .. |
---|
1390 | 1350 | { |
---|
1391 | 1351 | struct s3cmci_host *host = seq->private; |
---|
1392 | 1352 | |
---|
1393 | | - seq_printf(seq, "Register base = 0x%08x\n", (u32)host->base); |
---|
| 1353 | + seq_printf(seq, "Register base = 0x%p\n", host->base); |
---|
1394 | 1354 | seq_printf(seq, "Clock rate = %ld\n", host->clk_rate); |
---|
1395 | 1355 | seq_printf(seq, "Prescale = %d\n", host->prescaler); |
---|
1396 | 1356 | seq_printf(seq, "is2440 = %d\n", host->is2440); |
---|
.. | .. |
---|
1406 | 1366 | return 0; |
---|
1407 | 1367 | } |
---|
1408 | 1368 | |
---|
1409 | | -static int s3cmci_state_open(struct inode *inode, struct file *file) |
---|
1410 | | -{ |
---|
1411 | | - return single_open(file, s3cmci_state_show, inode->i_private); |
---|
1412 | | -} |
---|
1413 | | - |
---|
1414 | | -static const struct file_operations s3cmci_fops_state = { |
---|
1415 | | - .owner = THIS_MODULE, |
---|
1416 | | - .open = s3cmci_state_open, |
---|
1417 | | - .read = seq_read, |
---|
1418 | | - .llseek = seq_lseek, |
---|
1419 | | - .release = single_release, |
---|
1420 | | -}; |
---|
| 1369 | +DEFINE_SHOW_ATTRIBUTE(s3cmci_state); |
---|
1421 | 1370 | |
---|
1422 | 1371 | #define DBG_REG(_r) { .addr = S3C2410_SDI##_r, .name = #_r } |
---|
1423 | 1372 | |
---|
.. | .. |
---|
1459 | 1408 | return 0; |
---|
1460 | 1409 | } |
---|
1461 | 1410 | |
---|
1462 | | -static int s3cmci_regs_open(struct inode *inode, struct file *file) |
---|
1463 | | -{ |
---|
1464 | | - return single_open(file, s3cmci_regs_show, inode->i_private); |
---|
1465 | | -} |
---|
1466 | | - |
---|
1467 | | -static const struct file_operations s3cmci_fops_regs = { |
---|
1468 | | - .owner = THIS_MODULE, |
---|
1469 | | - .open = s3cmci_regs_open, |
---|
1470 | | - .read = seq_read, |
---|
1471 | | - .llseek = seq_lseek, |
---|
1472 | | - .release = single_release, |
---|
1473 | | -}; |
---|
| 1411 | +DEFINE_SHOW_ATTRIBUTE(s3cmci_regs); |
---|
1474 | 1412 | |
---|
1475 | 1413 | static void s3cmci_debugfs_attach(struct s3cmci_host *host) |
---|
1476 | 1414 | { |
---|
1477 | 1415 | struct device *dev = &host->pdev->dev; |
---|
| 1416 | + struct dentry *root; |
---|
1478 | 1417 | |
---|
1479 | | - host->debug_root = debugfs_create_dir(dev_name(dev), NULL); |
---|
1480 | | - if (IS_ERR(host->debug_root)) { |
---|
1481 | | - dev_err(dev, "failed to create debugfs root\n"); |
---|
1482 | | - return; |
---|
1483 | | - } |
---|
| 1418 | + root = debugfs_create_dir(dev_name(dev), NULL); |
---|
| 1419 | + host->debug_root = root; |
---|
1484 | 1420 | |
---|
1485 | | - host->debug_state = debugfs_create_file("state", 0444, |
---|
1486 | | - host->debug_root, host, |
---|
1487 | | - &s3cmci_fops_state); |
---|
1488 | | - |
---|
1489 | | - if (IS_ERR(host->debug_state)) |
---|
1490 | | - dev_err(dev, "failed to create debug state file\n"); |
---|
1491 | | - |
---|
1492 | | - host->debug_regs = debugfs_create_file("regs", 0444, |
---|
1493 | | - host->debug_root, host, |
---|
1494 | | - &s3cmci_fops_regs); |
---|
1495 | | - |
---|
1496 | | - if (IS_ERR(host->debug_regs)) |
---|
1497 | | - dev_err(dev, "failed to create debug regs file\n"); |
---|
| 1421 | + debugfs_create_file("state", 0444, root, host, &s3cmci_state_fops); |
---|
| 1422 | + debugfs_create_file("regs", 0444, root, host, &s3cmci_regs_fops); |
---|
1498 | 1423 | } |
---|
1499 | 1424 | |
---|
1500 | 1425 | static void s3cmci_debugfs_remove(struct s3cmci_host *host) |
---|
1501 | 1426 | { |
---|
1502 | | - debugfs_remove(host->debug_regs); |
---|
1503 | | - debugfs_remove(host->debug_state); |
---|
1504 | | - debugfs_remove(host->debug_root); |
---|
| 1427 | + debugfs_remove_recursive(host->debug_root); |
---|
1505 | 1428 | } |
---|
1506 | 1429 | |
---|
1507 | 1430 | #else |
---|
.. | .. |
---|
1518 | 1441 | int i, ret; |
---|
1519 | 1442 | |
---|
1520 | 1443 | host->is2440 = platform_get_device_id(pdev)->driver_data; |
---|
1521 | | - |
---|
1522 | | - for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) { |
---|
1523 | | - ret = gpio_request(i, dev_name(&pdev->dev)); |
---|
1524 | | - if (ret) { |
---|
1525 | | - dev_err(&pdev->dev, "failed to get gpio %d\n", i); |
---|
1526 | | - |
---|
1527 | | - for (i--; i >= S3C2410_GPE(5); i--) |
---|
1528 | | - gpio_free(i); |
---|
1529 | | - |
---|
1530 | | - return ret; |
---|
1531 | | - } |
---|
| 1444 | + pdata = pdev->dev.platform_data; |
---|
| 1445 | + if (!pdata) { |
---|
| 1446 | + dev_err(&pdev->dev, "need platform data"); |
---|
| 1447 | + return -ENXIO; |
---|
1532 | 1448 | } |
---|
1533 | 1449 | |
---|
1534 | | - if (!pdev->dev.platform_data) |
---|
1535 | | - pdev->dev.platform_data = &s3cmci_def_pdata; |
---|
1536 | | - |
---|
1537 | | - pdata = pdev->dev.platform_data; |
---|
| 1450 | + for (i = 0; i < 6; i++) { |
---|
| 1451 | + pdata->bus[i] = devm_gpiod_get_index(&pdev->dev, "bus", i, |
---|
| 1452 | + GPIOD_OUT_LOW); |
---|
| 1453 | + if (IS_ERR(pdata->bus[i])) { |
---|
| 1454 | + dev_err(&pdev->dev, "failed to get gpio %d\n", i); |
---|
| 1455 | + return PTR_ERR(pdata->bus[i]); |
---|
| 1456 | + } |
---|
| 1457 | + } |
---|
1538 | 1458 | |
---|
1539 | 1459 | if (pdata->no_wprotect) |
---|
1540 | 1460 | mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT; |
---|
.. | .. |
---|
1545 | 1465 | if (pdata->wprotect_invert) |
---|
1546 | 1466 | mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; |
---|
1547 | 1467 | |
---|
1548 | | - if (pdata->detect_invert) |
---|
1549 | | - mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; |
---|
1550 | | - |
---|
1551 | | - if (gpio_is_valid(pdata->gpio_detect)) { |
---|
1552 | | - ret = mmc_gpio_request_cd(mmc, pdata->gpio_detect, 0); |
---|
1553 | | - if (ret) { |
---|
1554 | | - dev_err(&pdev->dev, "error requesting GPIO for CD %d\n", |
---|
1555 | | - ret); |
---|
1556 | | - return ret; |
---|
1557 | | - } |
---|
| 1468 | + /* If we get -ENOENT we have no card detect GPIO line */ |
---|
| 1469 | + ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0); |
---|
| 1470 | + if (ret != -ENOENT) { |
---|
| 1471 | + dev_err(&pdev->dev, "error requesting GPIO for CD %d\n", |
---|
| 1472 | + ret); |
---|
| 1473 | + return ret; |
---|
1558 | 1474 | } |
---|
1559 | 1475 | |
---|
1560 | | - if (gpio_is_valid(pdata->gpio_wprotect)) { |
---|
1561 | | - ret = mmc_gpio_request_ro(mmc, pdata->gpio_wprotect); |
---|
1562 | | - if (ret) { |
---|
1563 | | - dev_err(&pdev->dev, "error requesting GPIO for WP %d\n", |
---|
1564 | | - ret); |
---|
1565 | | - return ret; |
---|
1566 | | - } |
---|
| 1476 | + ret = mmc_gpiod_request_ro(host->mmc, "wp", 0, 0); |
---|
| 1477 | + if (ret != -ENOENT) { |
---|
| 1478 | + dev_err(&pdev->dev, "error requesting GPIO for WP %d\n", |
---|
| 1479 | + ret); |
---|
| 1480 | + return ret; |
---|
1567 | 1481 | } |
---|
1568 | 1482 | |
---|
1569 | 1483 | return 0; |
---|
.. | .. |
---|
1576 | 1490 | struct mmc_host *mmc = host->mmc; |
---|
1577 | 1491 | int ret; |
---|
1578 | 1492 | |
---|
1579 | | - host->is2440 = (int) of_device_get_match_data(&pdev->dev); |
---|
| 1493 | + host->is2440 = (long) of_device_get_match_data(&pdev->dev); |
---|
1580 | 1494 | |
---|
1581 | 1495 | ret = mmc_of_parse(mmc); |
---|
1582 | 1496 | if (ret) |
---|
.. | .. |
---|
1596 | 1510 | struct s3cmci_host *host; |
---|
1597 | 1511 | struct mmc_host *mmc; |
---|
1598 | 1512 | int ret; |
---|
1599 | | - int i; |
---|
1600 | 1513 | |
---|
1601 | 1514 | mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev); |
---|
1602 | 1515 | if (!mmc) { |
---|
.. | .. |
---|
1640 | 1553 | "failed to get io memory region resource.\n"); |
---|
1641 | 1554 | |
---|
1642 | 1555 | ret = -ENOENT; |
---|
1643 | | - goto probe_free_gpio; |
---|
| 1556 | + goto probe_free_host; |
---|
1644 | 1557 | } |
---|
1645 | 1558 | |
---|
1646 | 1559 | host->mem = request_mem_region(host->mem->start, |
---|
.. | .. |
---|
1649 | 1562 | if (!host->mem) { |
---|
1650 | 1563 | dev_err(&pdev->dev, "failed to request io memory region.\n"); |
---|
1651 | 1564 | ret = -ENOENT; |
---|
1652 | | - goto probe_free_gpio; |
---|
| 1565 | + goto probe_free_host; |
---|
1653 | 1566 | } |
---|
1654 | 1567 | |
---|
1655 | 1568 | host->base = ioremap(host->mem->start, resource_size(host->mem)); |
---|
.. | .. |
---|
1661 | 1574 | |
---|
1662 | 1575 | host->irq = platform_get_irq(pdev, 0); |
---|
1663 | 1576 | if (host->irq <= 0) { |
---|
1664 | | - dev_err(&pdev->dev, "failed to get interrupt resource.\n"); |
---|
1665 | 1577 | ret = -EINVAL; |
---|
1666 | 1578 | goto probe_iounmap; |
---|
1667 | 1579 | } |
---|
.. | .. |
---|
1774 | 1686 | probe_free_mem_region: |
---|
1775 | 1687 | release_mem_region(host->mem->start, resource_size(host->mem)); |
---|
1776 | 1688 | |
---|
1777 | | - probe_free_gpio: |
---|
1778 | | - if (!pdev->dev.of_node) |
---|
1779 | | - for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) |
---|
1780 | | - gpio_free(i); |
---|
1781 | | - |
---|
1782 | 1689 | probe_free_host: |
---|
1783 | 1690 | mmc_free_host(mmc); |
---|
1784 | 1691 | |
---|
.. | .. |
---|
1804 | 1711 | { |
---|
1805 | 1712 | struct mmc_host *mmc = platform_get_drvdata(pdev); |
---|
1806 | 1713 | struct s3cmci_host *host = mmc_priv(mmc); |
---|
1807 | | - int i; |
---|
1808 | 1714 | |
---|
1809 | 1715 | s3cmci_shutdown(pdev); |
---|
1810 | 1716 | |
---|
.. | .. |
---|
1816 | 1722 | dma_release_channel(host->dma); |
---|
1817 | 1723 | |
---|
1818 | 1724 | free_irq(host->irq, host); |
---|
1819 | | - |
---|
1820 | | - if (!pdev->dev.of_node) |
---|
1821 | | - for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) |
---|
1822 | | - gpio_free(i); |
---|
1823 | 1725 | |
---|
1824 | 1726 | iounmap(host->base); |
---|
1825 | 1727 | release_mem_region(host->mem->start, resource_size(host->mem)); |
---|