0001
0002
0003
0004
0005
0006
0007 #include <linux/clk.h>
0008 #include <linux/device.h>
0009 #include <linux/module.h>
0010 #include <linux/of_device.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/pm_domain.h>
0013 #include <linux/pm_runtime.h>
0014 #include <linux/regmap.h>
0015
0016 #include <dt-bindings/power/imx8mp-power.h>
0017
0018 #define GPR_REG0 0x0
0019 #define PCIE_CLOCK_MODULE_EN BIT(0)
0020 #define USB_CLOCK_MODULE_EN BIT(1)
0021
0022 struct imx8mp_blk_ctrl_domain;
0023
0024 struct imx8mp_blk_ctrl {
0025 struct device *dev;
0026 struct notifier_block power_nb;
0027 struct device *bus_power_dev;
0028 struct regmap *regmap;
0029 struct imx8mp_blk_ctrl_domain *domains;
0030 struct genpd_onecell_data onecell_data;
0031 void (*power_off) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
0032 void (*power_on) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
0033 };
0034
0035 struct imx8mp_blk_ctrl_domain_data {
0036 const char *name;
0037 const char * const *clk_names;
0038 int num_clks;
0039 const char *gpc_name;
0040 };
0041
0042 #define DOMAIN_MAX_CLKS 2
0043
0044 struct imx8mp_blk_ctrl_domain {
0045 struct generic_pm_domain genpd;
0046 const struct imx8mp_blk_ctrl_domain_data *data;
0047 struct clk_bulk_data clks[DOMAIN_MAX_CLKS];
0048 struct device *power_dev;
0049 struct imx8mp_blk_ctrl *bc;
0050 int id;
0051 };
0052
0053 struct imx8mp_blk_ctrl_data {
0054 int max_reg;
0055 notifier_fn_t power_notifier_fn;
0056 void (*power_off) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
0057 void (*power_on) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
0058 const struct imx8mp_blk_ctrl_domain_data *domains;
0059 int num_domains;
0060 };
0061
0062 static inline struct imx8mp_blk_ctrl_domain *
0063 to_imx8mp_blk_ctrl_domain(struct generic_pm_domain *genpd)
0064 {
0065 return container_of(genpd, struct imx8mp_blk_ctrl_domain, genpd);
0066 }
0067
0068 static void imx8mp_hsio_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
0069 struct imx8mp_blk_ctrl_domain *domain)
0070 {
0071 switch (domain->id) {
0072 case IMX8MP_HSIOBLK_PD_USB:
0073 regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
0074 break;
0075 case IMX8MP_HSIOBLK_PD_PCIE:
0076 regmap_set_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN);
0077 break;
0078 default:
0079 break;
0080 }
0081 }
0082
0083 static void imx8mp_hsio_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
0084 struct imx8mp_blk_ctrl_domain *domain)
0085 {
0086 switch (domain->id) {
0087 case IMX8MP_HSIOBLK_PD_USB:
0088 regmap_clear_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
0089 break;
0090 case IMX8MP_HSIOBLK_PD_PCIE:
0091 regmap_clear_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN);
0092 break;
0093 default:
0094 break;
0095 }
0096 }
0097
0098 static int imx8mp_hsio_power_notifier(struct notifier_block *nb,
0099 unsigned long action, void *data)
0100 {
0101 struct imx8mp_blk_ctrl *bc = container_of(nb, struct imx8mp_blk_ctrl,
0102 power_nb);
0103 struct clk_bulk_data *usb_clk = bc->domains[IMX8MP_HSIOBLK_PD_USB].clks;
0104 int num_clks = bc->domains[IMX8MP_HSIOBLK_PD_USB].data->num_clks;
0105 int ret;
0106
0107 switch (action) {
0108 case GENPD_NOTIFY_ON:
0109
0110
0111
0112
0113 ret = clk_bulk_prepare_enable(num_clks, usb_clk);
0114 if (ret)
0115 return NOTIFY_BAD;
0116 regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
0117
0118 udelay(5);
0119
0120 regmap_clear_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
0121 clk_bulk_disable_unprepare(num_clks, usb_clk);
0122 break;
0123 case GENPD_NOTIFY_PRE_OFF:
0124
0125 ret = clk_bulk_prepare_enable(num_clks, usb_clk);
0126 if (ret)
0127 return NOTIFY_BAD;
0128
0129 regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
0130 break;
0131 case GENPD_NOTIFY_OFF:
0132 clk_bulk_disable_unprepare(num_clks, usb_clk);
0133 break;
0134 default:
0135 break;
0136 }
0137
0138 return NOTIFY_OK;
0139 }
0140
0141 static const struct imx8mp_blk_ctrl_domain_data imx8mp_hsio_domain_data[] = {
0142 [IMX8MP_HSIOBLK_PD_USB] = {
0143 .name = "hsioblk-usb",
0144 .clk_names = (const char *[]){ "usb" },
0145 .num_clks = 1,
0146 .gpc_name = "usb",
0147 },
0148 [IMX8MP_HSIOBLK_PD_USB_PHY1] = {
0149 .name = "hsioblk-usb-phy1",
0150 .gpc_name = "usb-phy1",
0151 },
0152 [IMX8MP_HSIOBLK_PD_USB_PHY2] = {
0153 .name = "hsioblk-usb-phy2",
0154 .gpc_name = "usb-phy2",
0155 },
0156 [IMX8MP_HSIOBLK_PD_PCIE] = {
0157 .name = "hsioblk-pcie",
0158 .clk_names = (const char *[]){ "pcie" },
0159 .num_clks = 1,
0160 .gpc_name = "pcie",
0161 },
0162 [IMX8MP_HSIOBLK_PD_PCIE_PHY] = {
0163 .name = "hsioblk-pcie-phy",
0164 .gpc_name = "pcie-phy",
0165 },
0166 };
0167
0168 static const struct imx8mp_blk_ctrl_data imx8mp_hsio_blk_ctl_dev_data = {
0169 .max_reg = 0x24,
0170 .power_on = imx8mp_hsio_blk_ctrl_power_on,
0171 .power_off = imx8mp_hsio_blk_ctrl_power_off,
0172 .power_notifier_fn = imx8mp_hsio_power_notifier,
0173 .domains = imx8mp_hsio_domain_data,
0174 .num_domains = ARRAY_SIZE(imx8mp_hsio_domain_data),
0175 };
0176
0177 #define HDMI_RTX_RESET_CTL0 0x20
0178 #define HDMI_RTX_CLK_CTL0 0x40
0179 #define HDMI_RTX_CLK_CTL1 0x50
0180 #define HDMI_RTX_CLK_CTL2 0x60
0181 #define HDMI_RTX_CLK_CTL3 0x70
0182 #define HDMI_RTX_CLK_CTL4 0x80
0183 #define HDMI_TX_CONTROL0 0x200
0184
0185 static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
0186 struct imx8mp_blk_ctrl_domain *domain)
0187 {
0188 switch (domain->id) {
0189 case IMX8MP_HDMIBLK_PD_IRQSTEER:
0190 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(9));
0191 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(16));
0192 break;
0193 case IMX8MP_HDMIBLK_PD_LCDIF:
0194 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
0195 BIT(7) | BIT(16) | BIT(17) | BIT(18) |
0196 BIT(19) | BIT(20));
0197 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11));
0198 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
0199 BIT(4) | BIT(5) | BIT(6));
0200 break;
0201 case IMX8MP_HDMIBLK_PD_PAI:
0202 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(17));
0203 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(18));
0204 break;
0205 case IMX8MP_HDMIBLK_PD_PVI:
0206 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(28));
0207 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(22));
0208 break;
0209 case IMX8MP_HDMIBLK_PD_TRNG:
0210 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(27) | BIT(30));
0211 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(20));
0212 break;
0213 case IMX8MP_HDMIBLK_PD_HDMI_TX:
0214 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
0215 BIT(2) | BIT(4) | BIT(5));
0216 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1,
0217 BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) |
0218 BIT(18) | BIT(19) | BIT(20) | BIT(21));
0219 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
0220 BIT(7) | BIT(10) | BIT(11));
0221 regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(1));
0222 break;
0223 case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY:
0224 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));
0225 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
0226 regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));
0227 break;
0228 default:
0229 break;
0230 }
0231 }
0232
0233 static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
0234 struct imx8mp_blk_ctrl_domain *domain)
0235 {
0236 switch (domain->id) {
0237 case IMX8MP_HDMIBLK_PD_IRQSTEER:
0238 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(9));
0239 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(16));
0240 break;
0241 case IMX8MP_HDMIBLK_PD_LCDIF:
0242 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
0243 BIT(4) | BIT(5) | BIT(6));
0244 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11));
0245 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
0246 BIT(7) | BIT(16) | BIT(17) | BIT(18) |
0247 BIT(19) | BIT(20));
0248 break;
0249 case IMX8MP_HDMIBLK_PD_PAI:
0250 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(18));
0251 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(17));
0252 break;
0253 case IMX8MP_HDMIBLK_PD_PVI:
0254 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(22));
0255 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(28));
0256 break;
0257 case IMX8MP_HDMIBLK_PD_TRNG:
0258 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(20));
0259 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(27) | BIT(30));
0260 break;
0261 case IMX8MP_HDMIBLK_PD_HDMI_TX:
0262 regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(1));
0263 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
0264 BIT(7) | BIT(10) | BIT(11));
0265 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1,
0266 BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) |
0267 BIT(18) | BIT(19) | BIT(20) | BIT(21));
0268 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
0269 BIT(2) | BIT(4) | BIT(5));
0270 break;
0271 case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY:
0272 regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));
0273 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
0274 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));
0275 break;
0276 default:
0277 break;
0278 }
0279 }
0280
0281 static int imx8mp_hdmi_power_notifier(struct notifier_block *nb,
0282 unsigned long action, void *data)
0283 {
0284 struct imx8mp_blk_ctrl *bc = container_of(nb, struct imx8mp_blk_ctrl,
0285 power_nb);
0286
0287 if (action != GENPD_NOTIFY_ON)
0288 return NOTIFY_OK;
0289
0290
0291
0292
0293
0294
0295
0296 regmap_write(bc->regmap, HDMI_RTX_RESET_CTL0, 0x0);
0297 regmap_write(bc->regmap, HDMI_RTX_CLK_CTL0, 0x0);
0298 regmap_write(bc->regmap, HDMI_RTX_CLK_CTL1, 0x0);
0299 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
0300 BIT(0) | BIT(1) | BIT(10));
0301 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(0));
0302
0303
0304
0305
0306
0307
0308 udelay(5);
0309
0310 return NOTIFY_OK;
0311 }
0312
0313 static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = {
0314 [IMX8MP_HDMIBLK_PD_IRQSTEER] = {
0315 .name = "hdmiblk-irqsteer",
0316 .clk_names = (const char *[]){ "apb" },
0317 .num_clks = 1,
0318 .gpc_name = "irqsteer",
0319 },
0320 [IMX8MP_HDMIBLK_PD_LCDIF] = {
0321 .name = "hdmiblk-lcdif",
0322 .clk_names = (const char *[]){ "axi", "apb" },
0323 .num_clks = 2,
0324 .gpc_name = "lcdif",
0325 },
0326 [IMX8MP_HDMIBLK_PD_PAI] = {
0327 .name = "hdmiblk-pai",
0328 .clk_names = (const char *[]){ "apb" },
0329 .num_clks = 1,
0330 .gpc_name = "pai",
0331 },
0332 [IMX8MP_HDMIBLK_PD_PVI] = {
0333 .name = "hdmiblk-pvi",
0334 .clk_names = (const char *[]){ "apb" },
0335 .num_clks = 1,
0336 .gpc_name = "pvi",
0337 },
0338 [IMX8MP_HDMIBLK_PD_TRNG] = {
0339 .name = "hdmiblk-trng",
0340 .clk_names = (const char *[]){ "apb" },
0341 .num_clks = 1,
0342 .gpc_name = "trng",
0343 },
0344 [IMX8MP_HDMIBLK_PD_HDMI_TX] = {
0345 .name = "hdmiblk-hdmi-tx",
0346 .clk_names = (const char *[]){ "apb", "ref_266m" },
0347 .num_clks = 2,
0348 .gpc_name = "hdmi-tx",
0349 },
0350 [IMX8MP_HDMIBLK_PD_HDMI_TX_PHY] = {
0351 .name = "hdmiblk-hdmi-tx-phy",
0352 .clk_names = (const char *[]){ "apb", "ref_24m" },
0353 .num_clks = 2,
0354 .gpc_name = "hdmi-tx-phy",
0355 },
0356 };
0357
0358 static const struct imx8mp_blk_ctrl_data imx8mp_hdmi_blk_ctl_dev_data = {
0359 .max_reg = 0x23c,
0360 .power_on = imx8mp_hdmi_blk_ctrl_power_on,
0361 .power_off = imx8mp_hdmi_blk_ctrl_power_off,
0362 .power_notifier_fn = imx8mp_hdmi_power_notifier,
0363 .domains = imx8mp_hdmi_domain_data,
0364 .num_domains = ARRAY_SIZE(imx8mp_hdmi_domain_data),
0365 };
0366
0367 static int imx8mp_blk_ctrl_power_on(struct generic_pm_domain *genpd)
0368 {
0369 struct imx8mp_blk_ctrl_domain *domain = to_imx8mp_blk_ctrl_domain(genpd);
0370 const struct imx8mp_blk_ctrl_domain_data *data = domain->data;
0371 struct imx8mp_blk_ctrl *bc = domain->bc;
0372 int ret;
0373
0374
0375 ret = pm_runtime_resume_and_get(bc->bus_power_dev);
0376 if (ret < 0) {
0377 dev_err(bc->dev, "failed to power up bus domain\n");
0378 return ret;
0379 }
0380
0381
0382 ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
0383 if (ret) {
0384 dev_err(bc->dev, "failed to enable clocks\n");
0385 goto bus_put;
0386 }
0387
0388
0389 bc->power_on(bc, domain);
0390
0391
0392 ret = pm_runtime_resume_and_get(domain->power_dev);
0393 if (ret < 0) {
0394 dev_err(bc->dev, "failed to power up peripheral domain\n");
0395 goto clk_disable;
0396 }
0397
0398 clk_bulk_disable_unprepare(data->num_clks, domain->clks);
0399
0400 return 0;
0401
0402 clk_disable:
0403 clk_bulk_disable_unprepare(data->num_clks, domain->clks);
0404 bus_put:
0405 pm_runtime_put(bc->bus_power_dev);
0406
0407 return ret;
0408 }
0409
0410 static int imx8mp_blk_ctrl_power_off(struct generic_pm_domain *genpd)
0411 {
0412 struct imx8mp_blk_ctrl_domain *domain = to_imx8mp_blk_ctrl_domain(genpd);
0413 const struct imx8mp_blk_ctrl_domain_data *data = domain->data;
0414 struct imx8mp_blk_ctrl *bc = domain->bc;
0415 int ret;
0416
0417 ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
0418 if (ret) {
0419 dev_err(bc->dev, "failed to enable clocks\n");
0420 return ret;
0421 }
0422
0423
0424 bc->power_off(bc, domain);
0425
0426 clk_bulk_disable_unprepare(data->num_clks, domain->clks);
0427
0428
0429 pm_runtime_put(domain->power_dev);
0430
0431
0432 pm_runtime_put(bc->bus_power_dev);
0433
0434 return 0;
0435 }
0436
0437 static struct generic_pm_domain *
0438 imx8m_blk_ctrl_xlate(struct of_phandle_args *args, void *data)
0439 {
0440 struct genpd_onecell_data *onecell_data = data;
0441 unsigned int index = args->args[0];
0442
0443 if (args->args_count != 1 ||
0444 index >= onecell_data->num_domains)
0445 return ERR_PTR(-EINVAL);
0446
0447 return onecell_data->domains[index];
0448 }
0449
0450 static struct lock_class_key blk_ctrl_genpd_lock_class;
0451
0452 static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)
0453 {
0454 const struct imx8mp_blk_ctrl_data *bc_data;
0455 struct device *dev = &pdev->dev;
0456 struct imx8mp_blk_ctrl *bc;
0457 void __iomem *base;
0458 int num_domains, i, ret;
0459
0460 struct regmap_config regmap_config = {
0461 .reg_bits = 32,
0462 .val_bits = 32,
0463 .reg_stride = 4,
0464 };
0465
0466 bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL);
0467 if (!bc)
0468 return -ENOMEM;
0469
0470 bc->dev = dev;
0471
0472 bc_data = of_device_get_match_data(dev);
0473 num_domains = bc_data->num_domains;
0474
0475 base = devm_platform_ioremap_resource(pdev, 0);
0476 if (IS_ERR(base))
0477 return PTR_ERR(base);
0478
0479 regmap_config.max_register = bc_data->max_reg;
0480 bc->regmap = devm_regmap_init_mmio(dev, base, ®map_config);
0481 if (IS_ERR(bc->regmap))
0482 return dev_err_probe(dev, PTR_ERR(bc->regmap),
0483 "failed to init regmap\n");
0484
0485 bc->domains = devm_kcalloc(dev, num_domains,
0486 sizeof(struct imx8mp_blk_ctrl_domain),
0487 GFP_KERNEL);
0488 if (!bc->domains)
0489 return -ENOMEM;
0490
0491 bc->onecell_data.num_domains = num_domains;
0492 bc->onecell_data.xlate = imx8m_blk_ctrl_xlate;
0493 bc->onecell_data.domains =
0494 devm_kcalloc(dev, num_domains,
0495 sizeof(struct generic_pm_domain *), GFP_KERNEL);
0496 if (!bc->onecell_data.domains)
0497 return -ENOMEM;
0498
0499 bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus");
0500 if (IS_ERR(bc->bus_power_dev))
0501 return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
0502 "failed to attach bus power domain\n");
0503
0504 bc->power_off = bc_data->power_off;
0505 bc->power_on = bc_data->power_on;
0506
0507 for (i = 0; i < num_domains; i++) {
0508 const struct imx8mp_blk_ctrl_domain_data *data = &bc_data->domains[i];
0509 struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i];
0510 int j;
0511
0512 domain->data = data;
0513
0514 for (j = 0; j < data->num_clks; j++)
0515 domain->clks[j].id = data->clk_names[j];
0516
0517 ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
0518 if (ret) {
0519 dev_err_probe(dev, ret, "failed to get clock\n");
0520 goto cleanup_pds;
0521 }
0522
0523 domain->power_dev =
0524 dev_pm_domain_attach_by_name(dev, data->gpc_name);
0525 if (IS_ERR(domain->power_dev)) {
0526 dev_err_probe(dev, PTR_ERR(domain->power_dev),
0527 "failed to attach power domain %s\n",
0528 data->gpc_name);
0529 ret = PTR_ERR(domain->power_dev);
0530 goto cleanup_pds;
0531 }
0532 dev_set_name(domain->power_dev, "%s", data->name);
0533
0534 domain->genpd.name = data->name;
0535 domain->genpd.power_on = imx8mp_blk_ctrl_power_on;
0536 domain->genpd.power_off = imx8mp_blk_ctrl_power_off;
0537 domain->bc = bc;
0538 domain->id = i;
0539
0540 ret = pm_genpd_init(&domain->genpd, NULL, true);
0541 if (ret) {
0542 dev_err_probe(dev, ret, "failed to init power domain\n");
0543 dev_pm_domain_detach(domain->power_dev, true);
0544 goto cleanup_pds;
0545 }
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557 lockdep_set_class(&domain->genpd.mlock,
0558 &blk_ctrl_genpd_lock_class);
0559
0560 bc->onecell_data.domains[i] = &domain->genpd;
0561 }
0562
0563 ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
0564 if (ret) {
0565 dev_err_probe(dev, ret, "failed to add power domain provider\n");
0566 goto cleanup_pds;
0567 }
0568
0569 bc->power_nb.notifier_call = bc_data->power_notifier_fn;
0570 ret = dev_pm_genpd_add_notifier(bc->bus_power_dev, &bc->power_nb);
0571 if (ret) {
0572 dev_err_probe(dev, ret, "failed to add power notifier\n");
0573 goto cleanup_provider;
0574 }
0575
0576 dev_set_drvdata(dev, bc);
0577
0578 return 0;
0579
0580 cleanup_provider:
0581 of_genpd_del_provider(dev->of_node);
0582 cleanup_pds:
0583 for (i--; i >= 0; i--) {
0584 pm_genpd_remove(&bc->domains[i].genpd);
0585 dev_pm_domain_detach(bc->domains[i].power_dev, true);
0586 }
0587
0588 dev_pm_domain_detach(bc->bus_power_dev, true);
0589
0590 return ret;
0591 }
0592
0593 static int imx8mp_blk_ctrl_remove(struct platform_device *pdev)
0594 {
0595 struct imx8mp_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
0596 int i;
0597
0598 of_genpd_del_provider(pdev->dev.of_node);
0599
0600 for (i = 0; bc->onecell_data.num_domains; i++) {
0601 struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i];
0602
0603 pm_genpd_remove(&domain->genpd);
0604 dev_pm_domain_detach(domain->power_dev, true);
0605 }
0606
0607 dev_pm_genpd_remove_notifier(bc->bus_power_dev);
0608
0609 dev_pm_domain_detach(bc->bus_power_dev, true);
0610
0611 return 0;
0612 }
0613
0614 #ifdef CONFIG_PM_SLEEP
0615 static int imx8mp_blk_ctrl_suspend(struct device *dev)
0616 {
0617 struct imx8mp_blk_ctrl *bc = dev_get_drvdata(dev);
0618 int ret, i;
0619
0620
0621
0622
0623
0624
0625
0626
0627
0628 ret = pm_runtime_get_sync(bc->bus_power_dev);
0629 if (ret < 0) {
0630 pm_runtime_put_noidle(bc->bus_power_dev);
0631 return ret;
0632 }
0633
0634 for (i = 0; i < bc->onecell_data.num_domains; i++) {
0635 struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i];
0636
0637 ret = pm_runtime_get_sync(domain->power_dev);
0638 if (ret < 0) {
0639 pm_runtime_put_noidle(domain->power_dev);
0640 goto out_fail;
0641 }
0642 }
0643
0644 return 0;
0645
0646 out_fail:
0647 for (i--; i >= 0; i--)
0648 pm_runtime_put(bc->domains[i].power_dev);
0649
0650 pm_runtime_put(bc->bus_power_dev);
0651
0652 return ret;
0653 }
0654
0655 static int imx8mp_blk_ctrl_resume(struct device *dev)
0656 {
0657 struct imx8mp_blk_ctrl *bc = dev_get_drvdata(dev);
0658 int i;
0659
0660 for (i = 0; i < bc->onecell_data.num_domains; i++)
0661 pm_runtime_put(bc->domains[i].power_dev);
0662
0663 pm_runtime_put(bc->bus_power_dev);
0664
0665 return 0;
0666 }
0667 #endif
0668
0669 static const struct dev_pm_ops imx8mp_blk_ctrl_pm_ops = {
0670 SET_SYSTEM_SLEEP_PM_OPS(imx8mp_blk_ctrl_suspend,
0671 imx8mp_blk_ctrl_resume)
0672 };
0673
0674 static const struct of_device_id imx8mp_blk_ctrl_of_match[] = {
0675 {
0676 .compatible = "fsl,imx8mp-hsio-blk-ctrl",
0677 .data = &imx8mp_hsio_blk_ctl_dev_data,
0678 }, {
0679 .compatible = "fsl,imx8mp-hdmi-blk-ctrl",
0680 .data = &imx8mp_hdmi_blk_ctl_dev_data,
0681 }, {
0682
0683 }
0684 };
0685 MODULE_DEVICE_TABLE(of, imx8m_blk_ctrl_of_match);
0686
0687 static struct platform_driver imx8mp_blk_ctrl_driver = {
0688 .probe = imx8mp_blk_ctrl_probe,
0689 .remove = imx8mp_blk_ctrl_remove,
0690 .driver = {
0691 .name = "imx8mp-blk-ctrl",
0692 .pm = &imx8mp_blk_ctrl_pm_ops,
0693 .of_match_table = imx8mp_blk_ctrl_of_match,
0694 },
0695 };
0696 module_platform_driver(imx8mp_blk_ctrl_driver);