struct scpi_opp *scpi_dvfs_get_opps(u8 domain) { struct scpi_data_buf sdata; struct mhu_data_buf mdata; struct __packed { u32 status; u32 header; struct scpi_opp_entry opp[MAX_DVFS_OPPS]; } buf; struct scpi_opp *opps; size_t opps_sz; int count, ret; if (domain >= MAX_DVFS_DOMAINS) return ERR_PTR(-EINVAL); if (scpi_opps[domain]) /* data already populated */ return scpi_opps[domain]; SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DVFS, SCPI_CMD_GET_DVFS_INFO, domain, buf); ret = scpi_execute_cmd(&sdata); if (ret) return ERR_PTR(ret); opps = kmalloc(sizeof(*opps), GFP_KERNEL); if (!opps) return ERR_PTR(-ENOMEM); count = DVFS_OPP_COUNT(buf.header); opps_sz = count * sizeof(*(opps->opp)); opps->count = count; opps->latency = DVFS_LATENCY(buf.header); opps->opp = kmalloc(opps_sz, GFP_KERNEL); if (!opps->opp) { kfree(opps); return ERR_PTR(-ENOMEM); } memcpy(opps->opp, &buf.opp[0], opps_sz); scpi_opps[domain] = opps; return opps; }
static struct scpi_dvfs_info *scpi_dvfs_get_info(u8 domain) { struct scpi_dvfs_info *info; struct scpi_opp *opp; struct dvfs_info buf; int ret, i; if (domain >= MAX_DVFS_DOMAINS) return ERR_PTR(-EINVAL); if (scpi_info->dvfs[domain]) /* data already populated */ return scpi_info->dvfs[domain]; ret = scpi_send_message(SCPI_CMD_GET_DVFS_INFO, &domain, sizeof(domain), &buf); if (ret) return ERR_PTR(ret); info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) return ERR_PTR(-ENOMEM); info->count = DVFS_OPP_COUNT(buf.header); info->latency = DVFS_LATENCY(buf.header) * 1000; /* uS to nS */ info->opps = kcalloc(info->count, sizeof(*opp), GFP_KERNEL); if (!info->opps) { kfree(info); return ERR_PTR(-ENOMEM); } for (i = 0, opp = info->opps; i < info->count; i++, opp++) { opp->freq = le32_to_cpu(buf.opps[i].freq); opp->m_volt = le32_to_cpu(buf.opps[i].m_volt); } scpi_info->dvfs[domain] = info; return info; }