#define SPIBASE_BYT            0x54
 #define SPIBASE_BYT_SZ         512
 #define SPIBASE_BYT_EN         BIT(1)
+#define BYT_BCR                        0xfc
+#define BYT_BCR_WPD            BIT(0)
 
 #define SPIBASE_LPT            0x3800
 #define SPIBASE_LPT_SZ         512
        return ret;
 }
 
+static bool lpc_ich_byt_set_writeable(void __iomem *base, void *data)
+{
+       u32 val;
+
+       val = readl(base + BYT_BCR);
+       if (!(val & BYT_BCR_WPD)) {
+               val |= BYT_BCR_WPD;
+               writel(val, base + BYT_BCR);
+               val = readl(base + BYT_BCR);
+       }
+
+       return val & BYT_BCR_WPD;
+}
+
+static bool lpc_ich_lpt_set_writeable(void __iomem *base, void *data)
+{
+       struct pci_dev *pdev = data;
+       u32 bcr;
+
+       pci_read_config_dword(pdev, BCR, &bcr);
+       if (!(bcr & BCR_WPD)) {
+               bcr |= BCR_WPD;
+               pci_write_config_dword(pdev, BCR, bcr);
+               pci_read_config_dword(pdev, BCR, &bcr);
+       }
+
+       return bcr & BCR_WPD;
+}
+
+static bool lpc_ich_bxt_set_writeable(void __iomem *base, void *data)
+{
+       unsigned int spi = PCI_DEVFN(13, 2);
+       struct pci_bus *bus = data;
+       u32 bcr;
+
+       pci_bus_read_config_dword(bus, spi, BCR, &bcr);
+       if (!(bcr & BCR_WPD)) {
+               bcr |= BCR_WPD;
+               pci_bus_write_config_dword(bus, spi, BCR, bcr);
+               pci_bus_read_config_dword(bus, spi, BCR, &bcr);
+       }
+
+       return bcr & BCR_WPD;
+}
+
 static int lpc_ich_init_spi(struct pci_dev *dev)
 {
        struct lpc_ich_priv *priv = pci_get_drvdata(dev);
        struct resource *res = &intel_spi_res[0];
        struct intel_spi_boardinfo *info;
-       u32 spi_base, rcba, bcr;
+       u32 spi_base, rcba;
 
        info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL);
        if (!info)
                if (spi_base & SPIBASE_BYT_EN) {
                        res->start = spi_base & ~(SPIBASE_BYT_SZ - 1);
                        res->end = res->start + SPIBASE_BYT_SZ - 1;
+
+                       info->set_writeable = lpc_ich_byt_set_writeable;
                }
                break;
 
                        res->start = spi_base + SPIBASE_LPT;
                        res->end = res->start + SPIBASE_LPT_SZ - 1;
 
-                       pci_read_config_dword(dev, BCR, &bcr);
-                       info->writeable = !!(bcr & BCR_WPD);
+                       info->set_writeable = lpc_ich_lpt_set_writeable;
+                       info->data = dev;
                }
                break;
 
                        res->start = spi_base & 0xfffffff0;
                        res->end = res->start + SPIBASE_APL_SZ - 1;
 
-                       pci_bus_read_config_dword(bus, spi, BCR, &bcr);
-                       info->writeable = !!(bcr & BCR_WPD);
+                       info->set_writeable = lpc_ich_bxt_set_writeable;
+                       info->data = bus;
                }
 
                pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x1);
 
 #define BCR            0xdc
 #define BCR_WPD                BIT(0)
 
+static bool intel_spi_pci_set_writeable(void __iomem *base, void *data)
+{
+       struct pci_dev *pdev = data;
+       u32 bcr;
+
+       /* Try to make the chip read/write */
+       pci_read_config_dword(pdev, BCR, &bcr);
+       if (!(bcr & BCR_WPD)) {
+               bcr |= BCR_WPD;
+               pci_write_config_dword(pdev, BCR, bcr);
+               pci_read_config_dword(pdev, BCR, &bcr);
+       }
+
+       return bcr & BCR_WPD;
+}
+
 static const struct intel_spi_boardinfo bxt_info = {
        .type = INTEL_SPI_BXT,
+       .set_writeable = intel_spi_pci_set_writeable,
 };
 
 static const struct intel_spi_boardinfo cnl_info = {
        .type = INTEL_SPI_CNL,
+       .set_writeable = intel_spi_pci_set_writeable,
 };
 
 static int intel_spi_pci_probe(struct pci_dev *pdev,
 {
        struct intel_spi_boardinfo *info;
        struct intel_spi *ispi;
-       u32 bcr;
        int ret;
 
        ret = pcim_enable_device(pdev);
        if (!info)
                return -ENOMEM;
 
-       /* Try to make the chip read/write */
-       pci_read_config_dword(pdev, BCR, &bcr);
-       if (!(bcr & BCR_WPD)) {
-               bcr |= BCR_WPD;
-               pci_write_config_dword(pdev, BCR, bcr);
-               pci_read_config_dword(pdev, BCR, &bcr);
-       }
-       info->writeable = !!(bcr & BCR_WPD);
-
+       info->data = pdev;
        ispi = intel_spi_probe(&pdev->dev, &pdev->resource[0], info);
        if (IS_ERR(ispi))
                return PTR_ERR(ispi);
 
  * @sregs: Start of software sequencer registers
  * @nregions: Maximum number of regions
  * @pr_num: Maximum number of protected range registers
- * @writeable: Is the chip writeable
  * @locked: Is SPI setting locked
  * @swseq_reg: Use SW sequencer in register reads/writes
  * @swseq_erase: Use SW sequencer in erase operation
        void __iomem *sregs;
        size_t nregions;
        size_t pr_num;
-       bool writeable;
        bool locked;
        bool swseq_reg;
        bool swseq_erase;
                                  INTEL_SPI_TIMEOUT * 1000);
 }
 
+static bool intel_spi_set_writeable(struct intel_spi *ispi)
+{
+       if (!ispi->info->set_writeable)
+               return false;
+
+       return ispi->info->set_writeable(ispi->base, ispi->info->data);
+}
+
 static int intel_spi_init(struct intel_spi *ispi)
 {
        u32 opmenu0, opmenu1, lvscc, uvscc, val;
                ispi->nregions = BYT_FREG_NUM;
                ispi->pr_num = BYT_PR_NUM;
                ispi->swseq_reg = true;
-
-               if (writeable) {
-                       /* Disable write protection */
-                       val = readl(ispi->base + BYT_BCR);
-                       if (!(val & BYT_BCR_WPD)) {
-                               val |= BYT_BCR_WPD;
-                               writel(val, ispi->base + BYT_BCR);
-                               val = readl(ispi->base + BYT_BCR);
-                       }
-
-                       ispi->writeable = !!(val & BYT_BCR_WPD);
-               }
-
                break;
 
        case INTEL_SPI_LPT:
                return -EINVAL;
        }
 
+       /* Try to disable write protection if user asked to do so */
+       if (writeable && !intel_spi_set_writeable(ispi)) {
+               dev_warn(ispi->dev, "can't disable chip write protection\n");
+               writeable = false;
+       }
+
        /* Disable #SMI generation from HW sequencer */
        val = readl(ispi->base + HSFSTS_CTL);
        val &= ~HSFSTS_CTL_FSMIE;
                /*
                 * If any of the regions have protection bits set, make the
                 * whole partition read-only to be on the safe side.
+                *
+                * Also if the user did not ask the chip to be writeable
+                * mask the bit too.
                 */
-               if (intel_spi_is_protected(ispi, base, limit))
-                       ispi->writeable = false;
+               if (!writeable || intel_spi_is_protected(ispi, base, limit))
+                       part->mask_flags |= MTD_WRITEABLE;
 
                end = (limit << 12) + 4096;
                if (end > part->size)
 
        ispi->dev = dev;
        ispi->info = info;
-       ispi->writeable = info->writeable;
 
        ret = intel_spi_init(ispi);
        if (ret)
 
        intel_spi_fill_partition(ispi, &part);
 
-       /* Prevent writes if not explicitly enabled */
-       if (!ispi->writeable || !writeable)
-               ispi->nor.mtd.flags &= ~MTD_WRITEABLE;
-
        ret = mtd_device_register(&ispi->nor.mtd, &part, 1);
        if (ret)
                return ERR_PTR(ret);
 
 /**
  * struct intel_spi_boardinfo - Board specific data for Intel SPI driver
  * @type: Type which this controller is compatible with
- * @writeable: The chip is writeable
+ * @set_writeable: Try to make the chip writeable (optional)
+ * @data: Data to be passed to @set_writeable can be %NULL
  */
 struct intel_spi_boardinfo {
        enum intel_spi_type type;
-       bool writeable;
+       bool (*set_writeable)(void __iomem *base, void *data);
+       void *data;
 };
 
 #endif /* INTEL_SPI_PDATA_H */